Я испытываю неожиданное взаимодействие между системными событиями и частотой обновления окна в простых приложениях Java2D в Linux/XWindows. Это лучше всего продемонстрировать с помощью небольшого примера ниже.Java2D: взаимодействие между событиями XWindows и частотой кадров
Эта программа создает небольшое окно, в котором полукруг отображается при разных оборотах. Графика обновляется со скоростью 60 кадров в секунду для создания мерцающего дисплея. Это достигается с помощью BufferStrategy
, а именно путем вызова метода show
.
Тем не менее, я отмечаю, что когда я (а) перемещаю мышь над окном, чтобы окно получало события с переносом мыши или (б) удерживало клавишу на клавиатуре, чтобы окно получало события клавиатуры, мерцание заметно увеличивается.
Поскольку скорость, с которой вызывается BufferStrategy.show()
, не зависит от этих событий, как видно из распечаток на консоли (они должны постоянно находиться на скорости около 60 кадров в секунду). Тем не менее, более быстрое мерцание указывает на то, что скорость, с которой дисплей фактически обновил, действительно изменился.
Мне кажется, что действительный, т. Е. Видимый 60 кадров в секунду, не достигается, если не генерируются события мыши или клавиатуры.
public class Test {
// pass the path to 'test.png' as command line parameter
public static void main(String[] args) throws Exception {
BufferedImage image = ImageIO.read(new File(args[0]));
// create window
JFrame frame = new JFrame();
Canvas canvas = new Canvas();
canvas.setPreferredSize(new Dimension(100, 100));
frame.getContentPane().add(canvas);
frame.pack();
frame.setVisible(true);
int fps = 0;
long nsPerFrame = 1000000000/60; // 60 = target fps
long showTime = System.nanoTime() + nsPerFrame;
long printTime = System.currentTimeMillis() + 1000;
for (int tick = 0; true; tick++) {
BufferStrategy bs = canvas.getBufferStrategy();
if (bs == null) {
canvas.createBufferStrategy(2);
continue;
}
// draw frame
Graphics g = bs.getDrawGraphics();
int framex = (tick % 4) * 64;
g.drawImage(image, 18, 18, 82, 82, framex, 0, framex+64, 64, null);
g.dispose();
bs.show();
// enforce frame rate
long sleepTime = showTime - System.nanoTime();
if (sleepTime > 0) {
long sleepMillis = sleepTime/1000000;
int sleepNanos = (int) (sleepTime - (sleepMillis * 1000000));
try {
Thread.sleep(sleepMillis, sleepNanos);
} catch (InterruptedException ie) {
/* ignore */
}
}
showTime += nsPerFrame;
// print frame rate achieved
fps++;
if (System.currentTimeMillis() > printTime) {
System.out.println("fps: " + fps);
fps = 0;
printTime += 1000;
}
}
}
}
Образец изображения для использования с этой программой (путь к которому должен быть передан в качестве аргумента командной строки) заключается в следующем:
Так что мой (2-часть) Вопрос в том, :
Почему этот эффект происходит? Как я могу достичь актуально 60 fps?
(Bonus вопрос комментаторам: вы испытываете тот же эффект также под другими операционными системами)
Я попытался запустить свой код несколько раз в моей машине, которая работает на окнах 10. Иногда я наблюдал, что мерцающий замедляется. Вы когда-нибудь сталкивались с этой проблемой? Вы пытались защитить свой код от потери кадров? –
@sbaitmangalkar Спасибо за попытку кода. Потеря кадров - это отдельный вопрос, который я сейчас не рассматриваю. Но просто чтобы быть ясным: когда вы запускаете программу, вы не видите ускорение анимации, как только вы перемещаете курсор мыши над окном? – Thomas
Буферы в стратегии буферов - это в основном 'VolatileImage', которые могут потерять содержимое на основе факторов ОС, как вы сказали, и, таким образом, в результате упомянутого поведения. Следовательно, ограничивая условие цикла для потерянных буферов, вы можете решить свою проблему. Опять же, я не уверен, действительно ли это причина поведения кода. –