【问题标题】:Java VSync without fullscreen window没有全屏窗口的 Java VSync
【发布时间】:2020-07-25 03:27:01
【问题描述】:

我正在尝试使我的窗口应用程序与显示器刷新进行垂直同步。此代码适用于“fullscreen = true”(报告 75FPS,显示器刷新率),但在窗口模式下它仅报告 32FPS。有人知道我在这里做错了什么吗?

import java.awt.BufferCapabilities;
import java.awt.GraphicsEnvironment;
import java.awt.ImageCapabilities;
import java.awt.image.BufferStrategy;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import sun.java2d.pipe.hw.ExtendedBufferCapabilities;

public class VSyncTest {

    public static void main(String args[]) {
        final boolean fullscreen = true;
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                JFrame v = new JFrame();
                if (fullscreen) {
                    GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(v);
                    v.createBufferStrategy(2);
                } else {
                    v.setVisible(true);
                    ExtendedBufferCapabilities b = new ExtendedBufferCapabilities(new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.PRIOR), ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
                    try {
                        v.createBufferStrategy(2, b);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                }
                new Thread() {
                    @Override
                    public void run() {
                        BufferStrategy bs = v.getBufferStrategy();
                        long start = System.nanoTime(), frames = 0;
                        do {
                            bs.getDrawGraphics();
                            bs.show();
                            frames++;
                            long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
                            long framesPerS = (long) (frames / (elapsed / 1000D));
                            if (frames % 60 == 0) {
                                System.out.println("Frames/s: " + framesPerS + ", Elapsed: " + elapsed / 1000);
                            }

                        } while (true);
                    }
                }.start();
            }
        });
    }
}

【问题讨论】:

    标签: java swing jframe fullscreen vsync


    【解决方案1】:

    我会尝试一个答案,尽管问题本身似乎不是 Java 问题,它似乎是图形问题。所以首先这个答案是基于我正在测试的配置,Windows 10,带英特尔显卡的戴尔笔记本电脑,2560x1440 显示器。

    其次是对您的代码的评论,以下设置在我的配置中惨遭失败:

    ExtendedBufferCapabilities b = new ExtendedBufferCapabilities(
        new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.PRIOR),
    ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
    

    它导致闪烁,帧计数器发疯。如果您查看 createBufferStrategy(2) 使用的代码 - 没有功能的重载 - 它使用 FlipContents.UNDEFINED 而不是 FlipContents.PRIOR。无论如何,我建议您使用

    GraphicsEnvironment.getLocalGraphicsEnvironment()
              .getDefaultScreenDevice()
              .getDefaultConfiguration()
              .getBufferCapabilities()
    

    为了获得适当的设备功能。那停止闪烁并将刷新率计固定为60 fps,这与我全屏运行的相同。

    另一件事是我尝试为框架设置实际尺寸并移除装饰。调用setUndecorated(true) 似乎没有任何区别,尽管建议在进入全屏之前调用它。最后,如果您调整窗口大小,计数器将再次关闭,因此看看您是否可以使用frame.setResizable( false ); 生存,如果您将帧移动到另一台显示器,则垂直同步丢失 - 您实际上可以看到帧计数器再次疯狂。不幸的是,我不是解释这些的图形专家,但如果我没记错的话,在设备上分配了一个缓冲区,并且在调整大小时需要使其失效——这就是为什么全屏毕竟是有意义的。我不记得我在哪里读过这个。

    【讨论】:

      猜你喜欢
      • 2012-07-06
      • 2011-07-20
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多