Screen tearing and fps drop on one screen but not on the other

Viewed 144

I'm trying to program a game in java, which basically constitutes mostly drawing a lot of image assets onto the screen.

That works great in basis, I have 70 frames per second on my main screen. The problem is that when I drag my gamewindow onto the other screen, suddenly it experiences screen tearing and severe framerate issues, only displaying 15-25 frames per second.

I've narrowed it down to 1 screen (Samsung TV) using properly configurated sun.java2d.d3d.D3DGraphicsConfig, while the other screen (laptop screen https://www.acer.com/ac/de/DE/content/series/nitro5) defaults to sun.awt.Win32GraphicsConfig.

I tried solutions from Java2D Performance Issues and FPS drops after loading images in java and changed all my images to properly configurated images with this code:

                final BufferedImage image = ImageIO.read(file);
                if(usedConfig != null) {
                    final BufferedImage compatibleImage = usedConfig.createCompatibleImage(image.getWidth(), image.getHeight(), image.getTransparency());
                    final Graphics2D g = compatibleImage.createGraphics();
                    g.drawImage(image, 0, 0, null);
                }
                currentImages.put(pathname+file.getName(), image);

I'm adjusting my config every frame with:

    GraphicsConfiguration currentConfig = null;
    if(Game.jpanel != null) {
        currentConfig = Game.board.getGraphicsConfiguration();
    }
    if(usedConfig != currentConfig) {
        System.out.println("config mismatch");
        if(usedConfig != null) {
            System.out.println(usedConfig.getClass().getName());
        }
        System.out.println(currentConfig.getClass().getName());
        usedConfig = currentConfig;
        firstCall = true;
    }
    if(firstCall != true) {
        return;
    }
    firstCall = false;
    ...//load and transform each image

The problem is that no matter what I do, it seems that on the slow screen nothing really helps, I'm stuck with at most 25 Frames per second.

I'm still working on this problem as you're reading this, so I will post an answer if I find one.

To simulate the problems you can try the VM option -Dsun.java2d.d3d=false with the following code:

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SmallestReproducableExample {
    public static int frames = 0;
    public static int fps = 0;
    public static void main(final String[] args) throws IOException {
        final String pathname = "./image.png";
        final File file = new File(pathname);
        final BufferedImage image = ImageIO.read(file);
        final JFrame frame = new JFrame("SmallestReproducableExample");
        frame.setDefaultCloseOperation
        (JFrame.EXIT_ON_CLOSE);

        final TimerTask fpsCounterTask = new TimerTask() {
            @Override
            public void run() {
                fps = frames;
                frames = 0;
            }
        };
        final Timer fpsCounter = new Timer();
        final Timer paintThread = new Timer();
        fpsCounter.schedule(fpsCounterTask, 1000, 1000);
        final JPanel board = new JPanel() {
            @Override
            public void paint(final Graphics g) {
                g.clearRect(-45, -45, 2041, 1041);
                for(int x = -40; x <= 2000; x+=40) {
                    for(int y = -40; y <= 1000; y+=40) {
                        g.drawImage(image, x, y, 40, 40, (ImageObserver)null);
                    }
                }
                for(int x = -41; x <= 2000; x+=40) {
                    for(int y = -41; y <= 1000; y+=40) {
                        g.drawImage(image, x, y, 40, 40, (ImageObserver)null);
                    }
                }
                for(int x = -42; x <= 2000; x+=40) {
                    for(int y = -42; y <= 1000; y+=40) {
                        g.drawImage(image, x, y, 40, 40, (ImageObserver)null);
                    }
                }
                frame.setTitle("SmallestReproducableExample fps: "+fps);
                final TimerTask repaintTask = new TimerTask() { //Task must be new otherwise it throws java.lang.IllegalStateException: Task already scheduled or cancelled
                    @Override
                    public void run() {
                        repaint();
                    }
                };
                ++frames;
                paintThread.schedule(repaintTask, 1);
            }
        };
        board.setSize((1900),(1070));
        board.setDoubleBuffered(true);
        frame.add(board);
        frame.setSize((1900),(1070));
        frame.setVisible(true);
        frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
    }
}

you obviously need your own test image with something transparent, as I can't provide one because of licenses.

1 Answers

Ok, update to the issue, if I enable the VM option -Dsun.java2d.opengl=true and plug out my other screen, then the opengl pipeline is enabled on the slow screen, resulting in high 60-70 fps, which wasn't possible previously.

But now when switching screens the other screen is slow.

I also need a way to enable the opengl pipeline on the fly programmatically to solve the issue completely.

Related