Screen tearing with BufferStrategy

I am using BufferStrategy with 2 buffers (tried with 3 as well) but I cannot rid of screen tearing in my application (no vsync?).
I draw everything on one BufferedImage and then draw it on the graphics received from BufferStrategy.

Any ideas how to solve this problem?

This is my render method:

    public void render() {
        do {
            do {
                Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
                g.setColor(Color.BLACK);
                g.fillRect(0, 0, getWidth(), getHeight());
                g.clipRect(0, 0, getWidth(), getHeight());
                g.scale(scale, scale);
                g.drawImage(screen.getImage(), 0, 0, screen.getWidth(), screen.getHeight(), null);
                g.dispose();
            } while (bufferStrategy.contentsRestored());
        } while (bufferStrategy.contentsLost());
        bufferStrategy.show();
    }

What Operating System are you using?

Seems you do triple buffering here :smiley:

try remove the do…while pair.

No the do-while pair is necessary. I also just noticed you have the show() call in the wrong place. It’s supposed to be right after the inner do-while loop ends, not after the outer one.

Really? I never used that before.

I have been telling people to do this since the beginning of time >.>

@ra4king: I have tearing on both Windows and Linux. Whole application is in JFrame - maybe that is an issue? Should I swap to applet?

You shouldn’t be seeing tearing in either Vista, 7, or 8. I don’t know about Linux.

Can we see the code/JAR to run it and see for ourselves?

Here is the jar: http://dl.dropbox.com/u/1146144/reckless-skirmishers.jar

Just go to the border of the pavement floor (go to the right) and move left-right repeatedly.
Game updates every 2nd frame but with 60 FPS - 60 updates I get tearing as well so I guess it is not a problem.

BTW: Graphics are for test purposes (taken from Catacomb Snatch).

No screen tearing here. It runs fine, but at 59 FPS? Something is wrong with your sleeping logic.

Are you using Windows 7?

Linux Ubuntu/Xubuntu and Windows 7. Now I am on the machine with Linux, tested it on friend’s xubuntu as well (maybe it is a xubuntu issue then).

Game loop implementation:

public class FixedLengthGameLoop implements GameLoop {
    private static final Logger LOGGER = LoggerFactory.getLogger(FixedLengthGameLoop.class);

    // Limits the update amounts before render
    private static final int MAX_UPDATES_PER_RENDER = Integer.MAX_VALUE;

    private static final double NANOS_PER_SECOND = 1000000000;

    // desired updates rate
    private static final double UPDATES_RATE = 30;

    // time between game updates
    private static final double UPDATES_INTERVAL = NANOS_PER_SECOND / UPDATES_RATE;

    // desired frame rate
    private static final double FRAMES_RATE = 60;

    // time between each render
    private static final double RENDERS_INTERVAL = NANOS_PER_SECOND / FRAMES_RATE;

    private GameContext context;

    public FixedLengthGameLoop(GameContext context) {
        LOGGER.info("Initializing default game loop");
        this.context = context;
    }

    public void run() {
        LOGGER.info("Executing main loop");

        double lastUpdateTime = System.nanoTime();
        double lastRenderTime = System.nanoTime();

        double now;
        int updatesCount;

        int frames = 0;
        int fps = (int) FRAMES_RATE;
        double lastFpsUpdateTime = System.nanoTime();

        while (context.isRunning()) {
            now = System.nanoTime();
            updatesCount = 0;

            while (now - lastUpdateTime > UPDATES_INTERVAL && updatesCount < MAX_UPDATES_PER_RENDER) {
                context.update();
                lastUpdateTime += UPDATES_INTERVAL;
                ++updatesCount;
            }

            if (now - lastRenderTime > RENDERS_INTERVAL) {
                float delta = Math.min(1.0f, (float) ((now - lastUpdateTime) / UPDATES_INTERVAL));
                context.render(delta, fps);
                lastRenderTime = now;
                ++frames;
            }

            if (now - lastFpsUpdateTime > NANOS_PER_SECOND) {
                fps = frames;
                frames = 0;
                lastFpsUpdateTime = now;
            }

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // consume
            }
        }
    }
}

Well on my machine even Catacomb Snatch have issues with vsync so I guess it is OS fault.

I’m pretty sure vsync is ignored in windowed mode for OpenGL on Windows and Linux and it uses whatever the desktop is set to. On most recent Linux distributions, I’ve found you can’t even get the desktop to use vsync.

This is Java2D, not OpenGL.

Also, in Windows Vista and 7, you shouldn’t be seeing any screen tearing due to the Desktop Window Compositor preventing any tearing.

Well it looks that I am doing something wrong. Now I/We have to figure out what is it :wink: