【问题标题】:JavaFX vs Swing renderingJavaFX 与 Swing 渲染
【发布时间】:2017-03-24 09:49:26
【问题描述】:

我正在使用 Swing 和 JavaFX 将图像渲染到屏幕上,但出现了意想不到的时机:目标只是在组件上的随机位置渲染 1,000,000 张图像。为什么 JavaFX 需要这么长时间?

结果:挥杆:2.5 秒。 JavaFX 8.5 秒。代码如下。

在 JavaFX 中。

public class JFXTest extends Application
{
public static void main(String[] args)
{
    launch(args);
}

@Override
public void start(Stage theStage)
{
    Group root = new Group();
    Scene theScene = new Scene( root );
    theStage.setScene( theScene );

    Canvas canvas = new Canvas( 1000, 1000);
    root.getChildren().add( canvas );

    GraphicsContext gc = canvas.getGraphicsContext2D();

    new ResourceLoaderJFX();
    System.out.println("Running test");

    Random ran = new Random();

    ClassLoader classLoader = getClass().getClassLoader();
    URL url = classLoader.getResource("sky.png");
    Image image = new Image(url.toString());
    long t1 = System.nanoTime();
    for (int j=0; j<1000000; j++ ) {
        int x = ran.nextInt(1000);
        int y = ran.nextInt(1000);
        gc.drawImage(image, x, y);
    }
    System.out.println("\n");
    long t2 = System.nanoTime()-t1;
    System.out.println("Took " + (t2/1000000000.0) + " secs");
    System.out.println("Done");

    theStage.show();
}
}

Prism pipeline init order: d3d sw 
Using native-based Pisces rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.sun.prism.d3d.D3DPipeline
Loading D3D native library ...
D3DPipelineManager: Created D3D9Ex device
    succeeded.
Direct3D initialization succeeded
(X) Got class = class com.sun.prism.d3d.D3DPipeline
Initialized prism pipeline: com.sun.prism.d3d.D3DPipeline
OS Information:
Maximum supported texture size: 8192
    Windows version 10.0 build 14393
Maximum texture size clamped to 4096
D3D Driver Information:
    Intel(R) Iris(TM) Graphics 540
    \\.\DISPLAY2
    Driver igdumdim64.dll, version 20.19.15.4463
    Pixel Shader version 3.0
    Device : ven_8086, dev_1926, subsys_00151414
    Max Multisamples supported: 4
 vsync: true vpipe: true
Running test

耗时 8.230974466 秒

在摇摆中:

public class SwingTest extends JPanel {

public void init() {
    setVisible(true);
}

public void runTest() {
    System.out.println("Running test");
    BufferedImage bufferedImage=null;
    try {
        bufferedImage = ImageIO.read(new File("C:\\Users\\resources\\png\\sky.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    long t1 = System.nanoTime();
    Random ran = new Random();
    for (int j=0; j<(1000000); j++ ) {
        int x = ran.nextInt(1000);
        int y = ran.nextInt(1000);
        this.getGraphics().drawImage(bufferedImage, x, y, null);
    }
    long t2 = System.nanoTime()-t1;
    System.out.println("Took " + (t2/1000000000.0) + " secs");
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame f = new JFrame();
            SwingTest view= new SwingTest();
            view.init();
            f.add(worldViewPanel);
            f.pack();
            f.setSize(new Dimension(1000,1000));
            f.setVisible(true);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            view.runTest();
        }
    });
}
}

Connected to the target VM, address: '127.0.0.1:53764', transport: 'socket'

耗时 2.586923483 秒

有趣的是,对于较低的数字

JAVAFX 10,000 张图像耗时 0.02173174 秒,第二次运行耗时 0.018200605 秒

摇摆 10,000 张图像耗时 0.138639497 秒,第二次运行耗时 0.13744251 秒

【问题讨论】:

  • 在您的代码中,JavaFX 渲染 1000K 图像,但 Swing 仅渲染 10K 图像。
  • 请为这两个示例提供SSCCE,以便我们了解您的测试是否正确。
  • 感谢您指出错字:为了便于阅读,我已经编辑了代码。我检查了两个例子中的数字,结果都是正确的。
  • 请提供完整的测试代码(以SSCCE的形式),以便我们了解您的测试是否正确
  • JavaFX:你似乎在计时ResourceLoaderJFX;当你profile 时,专注于它的方法。 Swing:代替getGraphics(),覆盖paintComponent()

标签: swing javafx


【解决方案1】:

我认为您遇到的是 JavaFX 的保留模式和 Swing 的立即模式之间的区别。 Swing 就是将这些图像直接传输到屏幕上,然后移动到下一个传输位置。当它需要再次绘制它们时,它会从头开始。碰巧,这非常快。

JavaFX 每次调用 drawImage(参见 GraphicsContext.writeImage())时都会创建一个不同的对象,然后将这些 Objects 保留在它从 Canvas 获取的内部缓冲区中。最重要的是,它创建了六个双打并将它们放入完全相同的缓冲区中(请参阅GraphicsContext.updateTransform())。

JavaFX 的卖点是它的留存模式。它将允许您在屏幕上操纵其Nodes,就好像它们处于 2-D(实际上是 3-D)坐标系中一样,并且它将“免费”执行此操作。如果您想在 2-D 场景中定位对象并四处移动它们,这是非常强大的,因为游戏程序员很清楚。

为此付出的代价是场景比 Swing 中的相应场景重得多,并且图像的内存成本在 JavaFX 应用程序中是累积的。在您的 JavaFX 应用程序中,您有一个 Scene,您正在向其中添加一个 Canvas,它正在创建一个场景图。 Swing 没有这样做。

如果您在分析器中运行您的程序,您可以准确地看到花费的时间,如果您在调试器中运行您的程序,您可以看到Canvas 缓冲区的大小。

【讨论】:

    【解决方案2】:

    您在这里将苹果与 bes 进行比较。在 Swing 中,实际上是在调用 drawImage 时渲染图像。在 JavaFX 中,这个绘制图像的命令只是添加到稍后将执行的命令缓冲区中。

    【讨论】:

      猜你喜欢
      • 2015-12-11
      • 2011-10-17
      • 1970-01-01
      • 2015-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      相关资源
      最近更新 更多