Графический интерфейс работает со скоростью 30 кадров в секунду?

Во время тестирования некоторого кода моделирования в реальном времени, который использует Swingworker, я заметил, что мой графический интерфейс всегда работает со скоростью 30 кадров в секунду, ни больше, ни меньше. Я обновляю графический интерфейс каждый раз, когда пользователь взаимодействует с приложением (например, движением мыши) или когда вызывается метод process() Swingworker. Swingworker ничего не делает прямо сейчас, он просто захватывает местоположение мыши из графического интерфейса и отправляет его обратно как клон через методы publish() и process() (я просто делаю это, чтобы посмотреть, что я могу и могу не делать при обмене данными между потоками, потому что многопоточность для меня все еще довольно нова). У меня нигде нет таймеров, метод process() Swingworker вызывает repaint() в графическом интерфейсе, поэтому мне было интересно, что заставляет графический интерфейс обновляться со скоростью 30 кадров в секунду? Может быть, по умолчанию активна vsync в графическом интерфейсе или это какое-то поведение метода process() в Swingworker? И наконец: есть ли способ увеличить частоту кадров?

Вот sscce, который демонстрирует такое поведение:

public class SimGameTest implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new SimGameTest());
    }

    @Override
    public void run() {
        MainWindow mainWindow = new MainWindow(new Game());

        mainWindow.setLocationRelativeTo(null);
        mainWindow.setVisible(true);
    }
}

public class MainWindow extends JFrame {
    private Game        game;
    private GamePanel   gamePanel;

    public MainWindow(Game game) {
        this.game = game;

        createAndShowGUI();

        startGame();
    }

    private void startGame() {
        GameSim gameSim = new GameSim(game, gamePanel);
        gameSim.execute();
    }

    private void createAndShowGUI() {
        setTitle("Sim game test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);

        JPanel contentPane = new JPanel(new GridBagLayout());

        gamePanel = new GamePanel(game);
        contentPane.add(gamePanel);

        add(contentPane);
        pack();
    }
}

public class Game {
    public Point            mouseLocation       = new Point();
    public Point            clonedMouseLocation = new Point();
}

public class GameSim extends SwingWorker<Point, Point> {
    private Game                game;
    private GamePanel           gamePanel;

    public GameSim(Game game, GamePanel gamePanel) {
        this.game = game;
        this.gamePanel = gamePanel;
    }

    @Override
    protected Point doInBackground() throws Exception {
        while (true) {
            publish((Point) game.mouseLocation.clone());
        }
    }

    @Override
    protected void process(List<Point> pointList) {
        game.clonedMouseLocation = pointList.get(pointList.size() - 1);
        gamePanel.repaint();
    }
}

public class GamePanel extends JPanel {
    private Game                game;
    private long                lastTime;

    public GamePanel(Game game) {
        this.game = game;
        setPreferredSize(new Dimension(512, 512));
    addMouseMotionListener(new GamePanelListener(););
    }

    @Override
    public void paintComponent(Graphics g) {
        // draw background
        g.setColor(new Color(0, 0, 32));
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(new Color(192, 192, 255));
        g.drawString(game.clonedMouseLocation.x + ", " + game.clonedMouseLocation.y, 10, 502);

        long now = System.nanoTime();
        long timePassed = now - lastTime;
        lastTime = now;
        double fps = ((double) 1000000000 / timePassed);
        g.drawString("fps: " + fps, 10, 482);
    }

    private class GamePanelListener extends MouseInputAdapter {
        @Override
        public void mouseMoved(MouseEvent e) {
            if (contains(e.getPoint())) {
                game.mouseLocation = e.getPoint();
            }
        }
    }
}

Я создал еще одну версию, в которой я просто подсчитываю, сколько раз графический интерфейс перерисовывался, и показываю количество на экране, и кажется, что оно увеличивается со скоростью 30 в секунду, поэтому я думаю, что подсчет кадров в секунду не является проблемой.


person Erik Stens    schedule 07.08.2012    source источник
comment
Пожалуйста, отредактируйте свой вопрос, включив в него sscce, который показывает скорость, которую вы описываете.   -  person trashgod    schedule 07.08.2012
comment
Как вы получаете частоту кадров?   -  person James Black    schedule 07.08.2012
comment
У меня в среднем около 24 кадров в секунду. Я думаю, вы обнаружите, что это зависит от реализации графического конвейера (DX или GL), аппаратного обеспечения, ОС и общей нагрузки на систему. Я также заставил его падать до 5 кадров в секунду, когда я помещал систему под нагрузку.   -  person MadProgrammer    schedule 07.08.2012
comment
Я также могу отключить его при большой нагрузке, но не поднять, поэтому мне интересно, что вызывает этот предел, если это какая-то часть Java или самой ОС. И можно ли обойти это с помощью другой техники?   -  person Erik Stens    schedule 07.08.2012
comment
Переключение на активный рендеринг должно повысить частоту кадров, пассивный и активный рендеринг.   -  person tenorsax    schedule 07.08.2012


Ответы (1)


Оказывается, SwingWorker публикует экземпляры Runnable в EventQueue, используя javax.swing.Timer именно с этим DELAY.

private static class DoSubmitAccumulativeRunnable 
      extends AccumulativeRunnable<Runnable> implements ActionListener {
    private final static int DELAY = (int) (1000 / 30);
    ...
}

Вы можете получить более высокую частоту кадров, но не с javax.swing.SwingWorker. Вы можете собрать SwingWorker из исходного кода, но в конечном итоге вы насытите поток экземплярами Runnable. Один из вариантов — запустить модель в полном объеме и периодически проверять ее, как показано здесь.

person trashgod    schedule 07.08.2012
comment
Я не знал об использовании javax.swing.SwingWorker javax.swing.Timer. - person trashgod; 07.08.2012
comment
Я обнаружил это вчера, отвечая на этот вопрос - person Robin; 07.08.2012