使用AWT/Swing获取显示器的刷新率:
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDisplayMode()
.getRefreshRate()
问题:使用JavaFX获得刷新率是否有类似的方法/程序?如果有,该怎么做?
使用AWT/Swing获取显示器的刷新率:
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDisplayMode()
.getRefreshRate()
问题:使用JavaFX获得刷新率是否有类似的方法/程序?如果有,该怎么做?
JavaFX 中没有等效的公共 API
这是DisplayMode.getRefreshRate()
您当前使用的 awt API 的 javadoc:
返回显示器的刷新率,以赫兹为单位。
没有等效的公共 JavaFX API。
如果公共 api 存在于 JavaFX 中,它可能可以通过Screen类访问,但那里没有定义此类功能的访问器。
有一个未记录的、不受支持的私有 API,它似乎提供了类似的功能:
com.sun.javafx.tk.Toolkit.getToolkit().getRefreshRate()
JavaFX 脉冲处理
有关 JavaFX 工作原理的相关信息可以在JavaFX 架构描述的脉冲文档中找到。
脉冲是一个事件,它向 JavaFX 场景图指示是时候将场景图上的元素状态与 Prism 同步了。脉冲以每秒 60 帧 (fps) 的最大值进行限制,并在动画在场景图上运行时触发。即使动画没有运行,当场景图中的某些内容发生变化时,也会安排一个脉冲。例如,如果按钮的位置发生变化,则会安排脉冲。
当触发脉冲时,场景图上元素的状态会同步到渲染层。
屏幕硬件刷新率与 JavaFX 内部脉冲处理率不同。虽然我猜在技术上可能这些可以在内部实现中同步(并且在某些情况下可能会发生),但公共文档中没有任何内容提到这是否真的发生。
关于自适应刷新技术的说明
另请注意,随着gsync 和自由同步等技术的出现,刷新率可以适应内容。
在大多数系统中,垂直同步是一种选择,在这些系统中,在显示器完成其当前刷新周期之前,视频卡无法对显示内存进行任何可见的操作。. . FreeSync 和 G-Sync 等技术颠覆了这一概念,使显示器的刷新率适应来自计算机的内容。此类技术需要视频适配器和显示器的特定支持。
这些技术使依赖显示器中的硬件刷新率的概念充其量有点模糊。
常见问题解答
您声明您查询显示刷新率的意图是:
就像绘制任何东西一样快,只要它仍然可以通过监视器实现......
默认情况下,JavaFX 有意限制为 60fps 帧速率,而不管显示器规格如何。
可以使用未记录的系统属性覆盖此上限,如下所述:
您可以使用未记录的功能来删除 JavaFX 中的帧速率上限,然后依靠底层视频卡驱动程序和硬件以屏幕底层硬件和软件功能内可用的最大速率进行渲染。
这是处理openjfx 源代码中的代码。
/*
* Called to set the value of PULSE_DURATION or PULSE_DURATION_NS based on
* the refresh rate of the primary screen (unless overridden by the
* FRAMERATE_PROP Setting). If the refresh rate can not be determined the
* default of 60hz is used.
*
* @param precision - precision in (1000 for ms or 1000000000 for ns)
*
* @return pulse duration value, either in ms or ns depending on the
* parameter.
*/
protected int getPulseDuration(int precision) {
int retVal = precision / 60;
// Allow Setting to override monitor refresh
if (Settings.get(FRAMERATE_PROP) != null) {
int overrideHz = Settings.getInt(FRAMERATE_PROP, 60);
if (overrideHz > 0) {
retVal = precision / overrideHz;
}
} else if (Settings.get(PULSE_PROP) != null) {
int overrideHz = Settings.getInt(PULSE_PROP, 60);
if (overrideHz > 0) {
retVal = precision / overrideHz;
}
} else {
// If not explicitly set in Settings, try to set based on
// refresh rate of display
int rate = Toolkit.getToolkit().getRefreshRate();
if (rate > 0) {
retVal = precision / rate;
}
// if unknown, use default
}
return retVal;
}
在源代码中,帧速率由未记录的属性控制javafx.animation.framerate
,该属性对应FRAMERATE_PROP
于上述源代码中的设置,并且javafx.animation.pulse
对应于设置PULSE_PROP
。
内部 Toolkit 类提供了一个备用 API 来使用显示器的刷新率。
javafx.animation.framerate
因此,也许您可以通过将系统属性设置为的值com.sun.javafx.tk.Toolkit.getToolkit().getRefreshRate()
或将两者都设置javafx.animation.framerate
为javafx.animation.pulse
null来实现您想要的。这个我没试过,所以不知道。需要注意确保您设置的值得到正确维护,并且不会被默认值覆盖。
您需要注意,如果您这样做,您将使用未记录的 API,因此这将需要打开适当的模块导出,以便 API 可以访问,并且在平台的未来版本中也可能被删除或变得不兼容,恕不另行通知(尽管这些设置目前多年来一直没有改变)。
所以我一直在阅读你提供的链接,对我来说,JavaFX 似乎只是停留在 60fps,因为它更喜欢?
默认情况下,是的,这是一个权衡。
对于通常使用 JavaFX 开发的应用程序类型,脉冲渲染机制内的最大刷新率为 60fps 通常就足够了,而不管设备的底层硬件功能如何。对于大多数 JavaFX 应用程序而言,将速率上限提高到该水平以上通常不是一个好的折衷方案,因为这意味着使用更高的资源(CPU 和视频处理能力以及功耗)来获得刷新更新的收益,而这些收益对于大多数用户来说通常是无法检测到的,而且通常不会底层硬件支持。
也就是说,如果您想覆盖此默认限制,如上所述,有一些未记录的方法可以做到这一点。
为什么不使用相同的方法?
在这种情况下,使用 AWT 方法可能是一个合理的选择。
硬件刷新不会根据所选的 UI 工具包而改变。
当前(JavaFX 17),JavaFX 系统依赖于java.awt
包(javafx.base
模块需要java.desktop
包含所有 awt 类的模块)。因此,如果 JavaFX 可用,那么java.awt.DisplayMode
该类也是可用的。
因此,如果目标是确定硬件刷新率,您可以使用现有的 awt API 来实现。
使用 Swing 或 JavaFX 时刷新率不会改变,对吗?
硬件刷新率不会因使用的 UI 工具包而改变。
JavaFX 中用于更新场景图渲染的场景图脉冲率的定义在某种程度上与刷新率有关,但它是 JavaFX 唯一的概念,因为 Swing 在其渲染阶段不使用场景图。