JavaFX ImageView显示高GPU

JavaFX ImageView显示高GPU,java,animation,javafx,animated-gif,Java,Animation,Javafx,Animated Gif,我正在创建JavaFX应用程序,并制作了一个加载场景。在这个场景中,我想显示一些文本,比如加载或初始化,并添加一些加载微调器动画图像,作为加载内容的视觉通知 我生成了一个通过创建的加载.gif动画,并将其像动画帧一样下载(多个.png文件) 我注意到,在JavaFX Scene Builder 8.5.0中,当我在ImageView中设置.gif时,我在NVidia GeForce RTX 2070图形卡上的Windows任务管理器中的GPU上升了20%,我认为这是一个问题。我使用javafx桌

我正在创建JavaFX应用程序,并制作了一个加载场景。在这个场景中,我想显示一些文本,比如加载或初始化,并添加一些加载微调器动画图像,作为加载内容的视觉通知

我生成了一个通过创建的加载.gif动画,并将其像动画帧一样下载(多个.png文件)

我注意到,在JavaFX Scene Builder 8.5.0中,当我在ImageView中设置.gif时,我在NVidia GeForce RTX 2070图形卡上的Windows任务管理器中的GPU上升了20%,我认为这是一个问题。我使用javafx桌面应用程序进行了测试,以排除场景生成器应用程序产生的问题,并得到了类似的结果

我尝试的下一步是使用javafx创建自定义动画。​动画。时间线。这是我从控制器初始化(URL位置,ResourceBundle资源)函数调用的初始化函数。此函数不使用.gif图像,而是使用同一.gif图像的多个.png图像作为帧

private void initializeAnimation() {
    imgLoading.setCache(true);
    imgLoading.setCacheHint(CacheHint.SPEED);
    Image[] images = new Image[31];
    for(int i = 0; i <= 30; i++){
        images[i] = new Image(getClass().getResourceAsStream("/es/main/gui/javafx/images/loading/frame-" + i + ".png"));
    }
    Timeline timeLine = new Timeline();
    Collection<KeyFrame> frames = timeLine.getKeyFrames();
    Duration frameGap = Duration.millis(100);
    Duration frameTime = Duration.ZERO;
    for (Image img : images) {
        frameTime = frameTime.add(frameGap);
        frames.add(new KeyFrame(frameTime, e -> imgLoading.setImage(img)));
    }
    timeLine.setCycleCount(Timeline.INDEFINITE);
    timeLine.play();
}
private void initializeAnimation(){
imgLoading.setCache(true);
imgLoading.setCacheHint(CacheHint.SPEED);
Image[]images=新图像[31];
对于(int i=0;i imgLoading.setImage(img));
}
timeLine.setCycleCount(timeLine.unfinite);
timeLine.play();
}
在第一个版本中,我没有调用.setCache()和.setCacheHint()函数,而是在测试同一代码的不同变体时添加了它们。我还尝试添加

-Dprism.forceGPU=true-Dsun.java2d.opengl=true-Dprism.order=es2、es1、sw、j2d

作为VMOption或我在本论坛上读到的关于改进java图形相关设置的一些变体。最后,在所有的更改之后,我的任务管理器中的结果并没有发生很大的变化。在当前版本中,我在这个场景中使用了高达17%的GPU

当场景结束时,在没有.gif图像或Timeline的下一个场景中,我的GPU几乎下降到0%

运行配置:

处理器:i9-9900KF

图形卡:GeForce RTX 2070

Java版本“1.8.0_251”

JavaFX版本“8.0.251-b08”

简短的总结问题:如何在JavaFX中正确显示动画.gif图像,而不会在GPU(或使用集成图形时的CPU)上产生巨大的开销

(编辑)14.09.2020-Java命名约定

我没有注意到的第一件事是,我在ImageView上没有使用相同的大小,因此我为测试更改的第一件事是将ImageView调整为与.gif图像相同的大小(ImageView和.gif图像的宽度和高度相同)。通过此更改,GPU百分比降低到大约%5

根据建议,我还升级了Java和JavaFX版本:

  • 尝试将JDK1.8.0ą与JavaFX内置版本8.0.261-b12一起使用,得到了类似的结果
  • 尝试将JDK14.0.2与JavaFXVersion15+9(最新的openjfx-15)一起使用,但仍然得到了类似的结果

  • 简短总结:升级Java和JavaFX版本并没有改变与此问题相关的任何内容。使用相同的大小会有所帮助,但我认为在您的帮助下,我可以做得更好。

    我的猜测是,如果您使用一个或多个
    旋转平移
    而不是关键帧动画,您可能会看到一些性能提升

    下面是一个简单的示例,在一个场景中使用多个转换:


    1.您真的认为在这样一个过时的JavaFX版本上研究性能问题值得吗?JavaFX15本周刚刚发布。2.为什么不提供一个小的、可复制的例子呢。这会增加你的机会,有人愿意花一些时间来分析你的问题。使用微调器的一帧并旋转它是个好主意,但它看起来不如我文章中链接中的动画好。在这个微调器中,如果你一帧一帧地分析图像,你会注意到它不仅会旋转,还会改变颜色的不透明度,但是对于简单的微调器来说,这是一个很好的主意。如果你想变得更有趣,你可以像和一样使用。我编辑了答案以适应。我将尝试,但我不确定为什么java在gif加载方面有问题。在过去,我在使用swing作为gui时遇到了类似的问题。
    import javafx.animation.RotateTransition;
    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class Main extends Application {
        @Override
        public void start(Stage stage) {
            Group root = new Group();
            Scene scene = new Scene(root, 500, 200);
            stage.setScene(scene);
    
            Rectangle rect = new Rectangle (100, 40, 100, 100);
            rect.setArcHeight(50);
            rect.setArcWidth(50);
            rect.setFill(Color.VIOLET);
        
            RotateTransition rt = new RotateTransition(Duration.millis(3000));
            rt.setByAngle(180);
            rt.setAutoReverse(true);
        
            FadeTransition ft = new FadeTransition(Duration.millis(3000));
            ft.setFromValue(1.0);
            ft.setToValue(0.3);
            ft.setCycleCount(4);
            ft.setAutoReverse(true);
    
            ParallelTransition pt = new ParallelTransition(rect, ft, rt);
            pt.play();            
    
            root.getChildren().add(rect);
    
            stage.show();
        
        }
        public static void main(String[] args) {
            launch(args);
        }
    }