获取 JavaFX 应用程序的帧速率的首选方法是什么?


这是一个

非常简单的问题:

获取 JavaFX 应用程序的帧速率的首选方法是什么?

谷歌从2009年开始查看结果,但该示例与JavaFX 1.x有关,并且一开始就以一种奇怪的方式(某种外部仪表)运行。找不到更好的例子,我在这里发帖。

我希望能够查询我的 JavaFX 应用程序(或如有必要,查询当前场景)并获取当前 FPS 是什么。

更新日期:2015年2月8日

下面发布了该问题的各种解决方案作为答案。我还发现以下博客文章引用了这个问题:http://tomasmikula.github.io/blog/2015/02/08/measuring-fps-with-reactfx.html

也就是说(由于以下解决方案的冗长)测量 FPS 被添加到 ReactFX 2.0 里程碑 2 中。很酷的旅行方式。

您可以使用AnimationTimer .

AnimationTimer的句柄方法在每帧上调用一次,传入的值是以纳秒为单位的当前时间(最佳近似值)。因此,您可以跟踪自上一帧以来的时间。

下面是一个实现,用于跟踪最后 100 帧的时间并使用它们计算帧速率:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class SimpleFrameRateMeter extends Application {
    private final long[] frameTimes = new long[100];
    private int frameTimeIndex = 0 ;
    private boolean arrayFilled = false ;
    @Override
    public void start(Stage primaryStage) {
        Label label = new Label();
        AnimationTimer frameRateMeter = new AnimationTimer() {
            @Override
            public void handle(long now) {
                long oldFrameTime = frameTimes[frameTimeIndex] ;
                frameTimes[frameTimeIndex] = now ;
                frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
                if (frameTimeIndex == 0) {
                    arrayFilled = true ;
                }
                if (arrayFilled) {
                    long elapsedNanos = now - oldFrameTime ;
                    long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
                    double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
                    label.setText(String.format("Current frame rate: %.3f", frameRate));
                }
            }
        };
        frameRateMeter.start();
        primaryStage.setScene(new Scene(new StackPane(label), 250, 150));
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

我只是复制了James_D程序并更改为使用性能跟踪器。 我从之前下载的程序复制的选项称为 JavaFXBalls3 . 这些选项似乎没有区别。

按任意键查看标签上的内容。 我的总是接近60。 也许更复杂的场景会更低。 AFAIK 60 是动画的最大值。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import com.sun.javafx.perf.PerformanceTracker;
import java.security.AccessControlException;
import javafx.animation.AnimationTimer;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class FPS extends Application {
    public static void main(String[] args) { launch(args); }
    private static PerformanceTracker tracker;
    @Override
    public void start(Stage stage) {
        VBox root = new VBox(20);
        Label label1 = new Label();
        Label label2 = new Label();
        root.getChildren().addAll(label1, label2);
        Scene scene = new Scene(root, 200, 100);
        try {
            System.setProperty("prism.verbose", "true");
            System.setProperty("prism.dirtyopts", "false");
            //System.setProperty("javafx.animation.fullspeed", "true");
            System.setProperty("javafx.animation.pulse", "10");
        } catch (AccessControlException e) {}
        scene.setOnKeyPressed((e)->{
            label2.setText(label1.getText());
        });
        stage.setScene(scene);
        stage.show();

        tracker = PerformanceTracker.getSceneTracker(scene);
        AnimationTimer frameRateMeter = new AnimationTimer() {
            @Override
            public void handle(long now) {
                label1.setText(String.format("Current frame rate: %.3f fps", getFPS()));
            }
        };
        frameRateMeter.start();
    }
    private float getFPS () {
        float fps = tracker.getAverageFPS();
        tracker.resetAverageFPS();
        return fps;
    }
}

James_D给出了一个朴素的实现,给出了瞬时FPS,他提出了一种更复杂的方法。我的尝试如下:

public class FXUtils
{
    private static long lastUpdate = 0;
    private static int index = 0;
    private static double[] frameRates = new double[100];
    static
    {
        AnimationTimer frameRateMeter = new AnimationTimer()
        {
            @Override
            public void handle(long now)
            {
                if (lastUpdate > 0)
                {
                    long nanosElapsed = now - lastUpdate;
                    double frameRate = 1000000000.0 / nanosElapsed;
                    index %= frameRates.length;
                    frameRates[index++] = frameRate;
                }
                lastUpdate = now;
            }
        };
        frameRateMeter.start();
    }
    /**
     * Returns the instantaneous FPS for the last frame rendered.
     *
     * @return
     */
    public static double getInstantFPS()
    {
        return frameRates[index % frameRates.length];
    }
    /**
     * Returns the average FPS for the last 100 frames rendered.
     * @return
     */
    public static double getAverageFPS()
    {
        double total = 0.0d;
        for (int i = 0; i < frameRates.length; i++)
        {
            total += frameRates[i];
        }
        return total / frameRates.length;
    }
}

相关内容

最新更新