Skip to main content

BufferStrategy problem with resize events

8 replies [Last post]
qu0ll
Offline
Joined: 2006-12-09
Points: 0

I am using BufferStrategy with 2 buffers to render off screen and then blast the contents on to the screen and I am impressed with the simplicity of it and its performance. However, there is a VERY serious problem with it, at least the way I am using it. It seems that whenever the JFrame is resized something is causing the screen to be cleared. The result is bad flickering or, even worse, a totally blank screen.

I am using BufferStrategy in the technique in the JavaDoc as follows:

<br />
do {<br />
	do {<br />
		g2d = (Graphics2D)this.strategy.getDrawGraphics();<br />
		// Perform rendering here...</p>
<p>		g2d.dispose();<br />
	} while (this.strategy.contentsRestored());<br />
	strategy.show();<br />
} while (strategy.contentsLost());<br />

The clearing of the screen happens after any calls to strategy.show() and even if I call it repeatedly after a resize event it seems that the screen will clear after the last call. All that is required to restore the screen's contents is to render again but I cannot work out how to trap this screen clearing event and therefore know when to re-render.

Why is the screen clearing after the frame is resized? Is there a way to prevent this, perhaps by using a different actual strategy for the BufferStrategy? The screen clearing after resizing doesn't occur if I just manually use a BufferedImage instead.

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
Qu0llSixFour@gmail.com
[Replace the "SixFour" with numbers to email me]

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Ken Warner

Are you overriding update() and paint() and do you
setIgnoreRepaint(true) on your component?

java2d@JAVADESKTOP.ORG wrote:
> I am using BufferStrategy with 2 buffers to render off screen and then blast the contents on to the screen and I am impressed with the simplicity of it and its performance. However, there is a VERY serious problem with it, at least the way I am using it. It seems that whenever the JFrame is resized something is causing the screen to be cleared. The result is bad flickering or, even worse, a totally blank screen.
>
> I am using BufferStrategy in the technique in the JavaDoc as follows:
>
> [code]
> do {
> do {
> g2d = (Graphics2D)this.strategy.getDrawGraphics();
> // Perform rendering here...
>
> g2d.dispose();
> } while (this.strategy.contentsRestored());
> strategy.show();
> } while (strategy.contentsLost());
> [/code]
>
> The clearing of the screen happens after any calls to strategy.show() and even if I call it repeatedly after a resize event it seems that the screen will clear after the last call. All that is required to restore the screen's contents is to render again but I cannot work out how to trap this screen clearing event and therefore know when to re-render.
>
> Why is the screen clearing after the frame is resized? Is there a way to prevent this, perhaps by using a different actual strategy for the BufferStrategy? The screen clearing after resizing doesn't occur if I just manually use a BufferedImage instead.
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

qu0ll
Offline
Joined: 2006-12-09
Points: 0

Hi Ken,

I realise that I need to override update() to just call paint() but what should I override paint() to do? Should it just call my rendering method?

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
Qu0llSixFour@gmail.com
[Replace the "SixFour" with numbers to email me]

qu0ll
Offline
Joined: 2006-12-09
Points: 0

OK I have it working by overriding paint() to call the rendering method but this seems like a bit of wasted effort, at least on some occasions. Anyway, it's working but I have noticed that almost every render has to happen twice because the strategy.contentsRestored() method returns true.

Is this normal? The following is a cut-down version of the code which exhibits this problem.

[code]
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class StrategyTest extends JFrame {

private class MyPanel extends JPanel {

public MyPanel() {
this.setIgnoreRepaint(true);
this.addComponentListener(new ComponentAdapter() {

@Override
public void componentResized(final ComponentEvent e) {
StrategyTest.this.render();
}
});
}
}

private final BufferStrategy strategy;

private Graphics2D g2d;

public StrategyTest() {
this.setLayout(new BorderLayout());
this.add(new MyPanel(), BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setSize(1024, 768);
this.setIgnoreRepaint(true);
this.createBufferStrategy(2);
this.strategy = this.getBufferStrategy();
}

public static void main(final String[] args) {
new StrategyTest().setVisible(true);
}

@Override
public void paint(final Graphics g) {
this.render();
}

public void render() {
if (this.strategy == null) {
return;
}
do {
do {
this.g2d = (Graphics2D)this.strategy.getDrawGraphics();
this.drawBox();
this.g2d.dispose();
if (!this.strategy.contentsRestored()) {
break;
} else {
System.out.println("### BUFFER CONTENTS RESTORED ###");
}
} while (true);
this.strategy.show();
if (!this.strategy.contentsLost()) {
break;
} else {
System.out.println("### BUFFER CONTENTS LOST ###");
}
} while (true);
}

@Override
public void update(final Graphics g) {
this.paint(g);
}

private void drawBox() {
this.g2d.setColor(Color.RED);
this.g2d.fillRect(20, 20, this.getWidth() - 40, this.getHeight() - 40);
}
}
[/code]

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
Qu0llSixFour@gmail.com
[Replace the "SixFour" with numbers to email me]

Ken Warner

I would revert to the use of the Java Docs recommended do/while loops.
They work well. And you will have to figure out when to call your
rendering method.

I use MemoryImageSource and render with the do/while loops
in my newPixels() method. I use paint() with the do/while
loops for expose events. And I toggle setIgnoreRepaint()
as needed.

The mods to you've made to the do/while loops look unnecessary.
But our apps are different.

You are on the right track. Don't forget about overriding update().

java2d@JAVADESKTOP.ORG wrote:
> OK I have it working by overriding paint() to call the rendering method but this seems like a bit of wasted effort, at least on some occasions. Anyway, it's working but I have noticed that almost every render has to happen twice because the strategy.contentsRestored() method returns true.
>
> Is this normal? The following is a cut-down version of the code which exhibits this problem.
>
> [code]
> import java.awt.BorderLayout;
> import java.awt.Color;
> import java.awt.Graphics;
> import java.awt.Graphics2D;
> import java.awt.event.ComponentAdapter;
> import java.awt.event.ComponentEvent;
> import java.awt.image.BufferStrategy;
>
> import javax.swing.JFrame;
> import javax.swing.JPanel;
>
> public class StrategyTest extends JFrame {
>
> private class MyPanel extends JPanel {
>
> public MyPanel() {
> this.setIgnoreRepaint(true);
> this.addComponentListener(new ComponentAdapter() {
>
> @Override
> public void componentResized(final ComponentEvent e) {
> StrategyTest.this.render();
> }
> });
> }
> }
>
> private final BufferStrategy strategy;
>
> private Graphics2D g2d;
>
> public StrategyTest() {
> this.setLayout(new BorderLayout());
> this.add(new MyPanel(), BorderLayout.CENTER);
> this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
> this.pack();
> this.setSize(1024, 768);
> this.setIgnoreRepaint(true);
> this.createBufferStrategy(2);
> this.strategy = this.getBufferStrategy();
> }
>
> public static void main(final String[] args) {
> new StrategyTest().setVisible(true);
> }
>
> @Override
> public void paint(final Graphics g) {
> this.render();
> }
>
> public void render() {
> if (this.strategy == null) {
> return;
> }
> do {
> do {
> this.g2d = (Graphics2D)this.strategy.getDrawGraphics();
> this.drawBox();
> this.g2d.dispose();
> if (!this.strategy.contentsRestored()) {
> break;
> } else {
> System.out.println("### BUFFER CONTENTS RESTORED ###");
> }
> } while (true);
> this.strategy.show();
> if (!this.strategy.contentsLost()) {
> break;
> } else {
> System.out.println("### BUFFER CONTENTS LOST ###");
> }
> } while (true);
> }
>
> @Override
> public void update(final Graphics g) {
> this.paint(g);
> }
>
> private void drawBox() {
> this.g2d.setColor(Color.RED);
> this.g2d.fillRect(20, 20, this.getWidth() - 40, this.getHeight() - 40);
> }
> }
> [/code]
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

qu0ll
Offline
Joined: 2006-12-09
Points: 0

Hi Ken,

Thanks for your input.

> I would revert to the use of the Java Docs recommended do/while loops.
> They work well.

How are my loops any different other than printing out the return statuses?

> And you will have to figure out when to call your
> rendering method.

Yes, that's what I am requesting assistance with. The problem seems to be that if I don't override paint() to call the renderer then as soon as the user clicks and holds on the border of the frame, the contents of the frame are cleared. Perhaps as Dmitri points out this is just a Vista/Aero thing.

> I use MemoryImageSource and render with the do/while loops
> in my newPixels() method. I use paint() with the do/while
> loops for expose events. And I toggle setIgnoreRepaint()
> as needed.

Does this have any advantages over what I am doing?

> The mods to you've made to the do/while loops look unnecessary.
> But our apps are different.

As I said, I don't see how my loops are any different.

> You are on the right track. Don't forget about overriding update().

I do override update().

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
Qu0llSixFour@gmail.com
[Replace the "SixFour" with numbers to email me]

Dmitri Trembovetski

What platform and Java version is this with?

Thanks,
Dmitri

java2d@JAVADESKTOP.ORG wrote:
> I am using BufferStrategy with 2 buffers to render off screen and then blast the contents on to the screen and I am impressed with the simplicity of it and its performance. However, there is a VERY serious problem with it, at least the way I am using it. It seems that whenever the JFrame is resized something is causing the screen to be cleared. The result is bad flickering or, even worse, a totally blank screen.
>
> I am using BufferStrategy in the technique in the JavaDoc as follows:
>
> [code]
> do {
> do {
> g2d = (Graphics2D)this.strategy.getDrawGraphics();
> // Perform rendering here...
>
> g2d.dispose();
> } while (this.strategy.contentsRestored());
> strategy.show();
> } while (strategy.contentsLost());
> [/code]
>
> The clearing of the screen happens after any calls to strategy.show() and even if I call it repeatedly after a resize event it seems that the screen will clear after the last call. All that is required to restore the screen's contents is to render again but I cannot work out how to trap this screen clearing event and therefore know when to re-render.
>
> Why is the screen clearing after the frame is resized? Is there a way to prevent this, perhaps by using a different actual strategy for the BufferStrategy? The screen clearing after resizing doesn't occur if I just manually use a BufferedImage instead.
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

qu0ll
Offline
Joined: 2006-12-09
Points: 0

Sorry Dmitri, very unprofessional of me.

It's Windows Vista and JSE 6 Update 10 b26.

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
Qu0llSixFour@gmail.com
[Replace the "SixFour" with numbers to email me]

Dmitri Trembovetski

Hi,

java2d@JAVADESKTOP.ORG wrote:
> Sorry Dmitri, very unprofessional of me.
>
> It's Windows Vista and JSE 6 Update 10 b26.

First, on Vista with Aero enabled you'd get
that black flashing occasionally, this is just
the way Aero works. You can get the same artifacts
with "native" Direct3D applications.

Second, you should disable repaints with setIgnoreRepaint().
You don't need to override paint/update in this case - they
won't be called.

In fact, using paint()/update() with BufferStrategy
is mixing two different painting concepts - active
and passive rendering.
http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html
This is applicable to windowed mode as well.

Typically with BufferStrategy one would use
active rendering, meaning that there's a thread with
a rendering loop which does all the rendering, and
the usual repainting mechanism is turned off.

run() {
do {
collectUserInput();
changeWorldState();
render();
} while (true);
}

As for the resizing artifacts,
I'm wondering if you could somewhat reduce the
artifacts during resize if you attach drag/resize
listener to your window and pause your rendering
loop until the window stopped resizing. It probably
won't look pretty during the resize but you may
avoid flashing.

Thanks,
Dmitri

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".