gpt4 book ai didi

Java2D : interaction between XWindows events and frame rate

转载 作者:搜寻专家 更新时间:2023-10-30 21:11:01 26 4
gpt4 key购买 nike

我在 Linux/XWindows 上的简单 Java2D 应用程序中遇到系统事件和窗口刷新率之间的意外交互。下面的小示例可以很好地证明这一点。

这个程序创建了一个小窗口,其中半圆以不同的旋转度显示。图形以每秒 60 帧的速度更新,以产生闪烁的显示。这是通过 BufferStrategy 实现的,即调用其 show 方法。

但是,我注意到当我 (a) 将鼠标移到窗口上以便窗口接收鼠标悬停事件或 (b) 按住键盘上的某个键以便窗口接收键盘事件时,闪烁会增加可见。

因为调用 BufferStrategy.show() 的速率不受这些事件的影响,从控制台上的打印输出可以看出(它们应该始终保持在 60 fps 左右).但是,更快的闪烁表明显示实际更新的速率确实发生了变化。

在我看来,实际,即每秒可见 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;
}
}
}
}

与此程序一起使用的示例图像(必须作为命令行参数传递到的路径)是这样的:

enter image description here

所以我的(两部分)问题是:

为什么会发生这种效应?如何才能达到实际 60 fps?

(评论者的奖励问题:您在其他操作系统下是否也遇到过相同的效果?)

最佳答案

:为什么会发生这种效应?

简答:必须在之后调用 canvas.getToolkit().sync()Toolkit.getDefaultToolkit().sync() BufferStrategy#show

长答案:如果没有明确的 Toolkit#sync 像素不会出现在屏幕上,直到 X11 命令缓冲区已满或其他事件(例如鼠标移动)强制同花顺。

引自 http://www.java-gaming.org/index.php/topic,15000 .

... even if we (Java2D) issue our rendering commands immediately the video driver may chose not to execute them right away. Classic example is X11 - try timing a loop of Graphics.fillRects - see how many you can issue in a couple of seconds. Without toolkit.sync() (which in case of X11 pipeline does XFlush()) after each call or at the end of the loop what you actually measure is how fast Java2D can call X11 lib's XFillRect method, which just batches up those calls until it's command buffer is full, only then they're sent to the X server for execution.

:如何才能达到实际的 60 fps?

A:刷新命令缓冲区并考虑使用 System.setProperty("sun.java2d.opengl", "true"); 为 Java2D 打开 OpenGL 加速code 或 -Dsun.java2d.opengl=true 命令行选项。

另见:

关于Java2D : interaction between XWindows events and frame rate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40661638/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com