简体   繁体   English

全屏帧率限制难题

[英]Full-screen frame-rate limit conundrum

my game(framework) can't go faster than 30 frames per second(about 33 ms between update calls) in full-screen. 我的游戏(框架)在全屏状态下的运行速度不能超过每秒30帧(两次更新调用之间约33毫秒)。 I use a Timer for the loop. 我使用一个计时器循环。 Actually it gets a bit more complicated, since when i decrease the delay incrementally, the time between calls i measure goes nuts. 实际上,它变得有点复杂,因为当我逐渐减少延迟时,我测量的两次呼叫之间的时间就变得很疯狂。 It jumps form the set delay to twice or more the expected value. 它从设置的延迟跳到期望值的两倍或更多。 The threshold seems to be 30 ms. 该阈值似乎是30毫秒。 No problem in windowed mode, where discrepancies start to appear at the 4 ms threshold. 在窗口模式下没有问题,在该模式下,差异开始出现在4 ms阈值处。 Both modes act normally at higher delays. 两种模式通常以较高的延迟起作用。 Here are parts of the code that I think are pertinent. 这是我认为相关的部分代码。

fps = 30;       
timer = new Timer(1000/fps, new ActionListener() {          
@Override
public void actionPerformed(ActionEvent arg0) {
    tick();             
}

Above is the Timer setup. 以上是计时器设置。 Below is the rest. 下面是其余的。

private void tick(){
    update(gameTime);
    draw(gameTime);     
}

Here is my Graphics(2D) and BufferedImage. 这是我的Graphics(2D)和BufferedImage。

    public DrawBatch(DeviceManager deviceManager) {
    this.deviceManager = deviceManager;
    color = Color.MAGENTA;
    bufferedImage = deviceManager.getBufferedImage();       
    bufferedGraphics = (Graphics2D)bufferedImage.getGraphics();bufferedGraphics = (Graphics2D)bufferedImage.getGraphics();
    bufferedGraphics.setBackground(color);
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 
}

The draw(GameTime gameTime) method begins with this method: draw(GameTime gameTime)方法从以下方法开始:

    public void begin(){
    bufferedGraphics.clearRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());  
}

Now we can draw using bufferedGraphics. 现在我们可以使用bufferedGraphics进行绘制了。 draw(GT gT) ends with this.(inspired by xna) draw(GT gT)以此结尾。(灵感来自xna)

    public void end(){
    if(deviceManager.isFullScreen())deviceManager.getGraphics().drawImage(bufferedImage, 0,0, null);
    else deviceManager.getGraphics().drawImage(bufferedImage, 3,25, null);      
    deviceManager.getGraphics().dispose();      
    bufferedImage.flush();  
}

I recycle the same BufferedImage since making new one(along with a Graphics object) made one hell of a memory leak. 我循环使用相同的BufferedImage,因为制作新的(与Graphics对象一起)使一次内存泄漏成为了现实。 Don't know if using the same Graphics object instead of doing .dispose() / new Graphics every frame. 不知道是否使用相同的Graphics对象,而不是每帧都使用.dispose()/ new Graphics。

In windowed mode, the BufferedImage is drawn on jFrame.getGraphics() and in fulls-creen on graphicDevice.getFullScreenWindow().getGraphics(). 在窗口模式下,BufferedImage绘制在jFrame.getGraphics()上,而全画幅绘制在graphicDevice.getFullScreenWindow()。getGraphics()上。

Here is the full-screen setup. 这是全屏设置。

public void setFS(){
    jFrame.setVisible(false);
    jFrame.dispose();
    jFrame.setIgnoreRepaint(true);
    jFrame.setResizable(false);
    jFrame.setUndecorated(true);
    graphicDevice.setFullScreenWindow(jFrame);
    graphicDevice.getFullScreenWindow().setIgnoreRepaint(true);
    graphicDevice.setDisplayMode(new DisplayMode(width, height, 32, 60));   
    jFrame.setVisible(true);        
    fullScreen = true;      
}

And the windowed setup. 和窗口设置。

public void setW(){
    jFrame.setVisible(false);
    jFrame.dispose();   
    jFrame.setIgnoreRepaint(true);
    jFrame.setResizable(false);
    jFrame.setUndecorated(false);
    graphicDevice.setFullScreenWindow(null);
    jFrame.setSize(width, height);      
    jFrame.setVisible(true);
    jFrame.getContentPane().setPreferredSize(new Dimension(800, 600));          
    jFrame.pack();      
    fullScreen = false;
}   

Any idea why the different behaviors of the modes? 知道为什么模式的行为不同吗? (Except for the frame-rate and some potential memory leaks, the program runs smoothly.) (除了帧速率和一些潜在的内存泄漏,该程序运行平稳。)

Theoretically, the timer's period can be no shorter than the time taken to render one frame. 从理论上讲,计时器的周期不能短于渲染一帧所花费的时间。 Practically, it needs to be longer or you'll immediately saturate the timer's shared thread. 实际上,它需要更长的时间,否则您将立即饱和计时器的共享线程。 You'll need to profile to be sure. 您需要进行个人资料确定。 Calls to drawImage() typically dominate, even without scaling. 即使没有缩放比例,对drawImage()调用通常仍占主导地位。 This AnimationTest displays a moving average of the render time over the last few FRAMES . AnimationTest显示最后几个FRAMES的渲染时间的移动平均值。 You can use the approach to tune your implementation to suit your slowest acceptable target platform. 您可以使用该方法来调整实现,以适应最慢的可接受目标平台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM