【问题标题】:How do I pause the redraw in XNA?如何在 XNA 中暂停重绘?
【发布时间】:2013-05-09 09:57:45
【问题描述】:

我制作了一个 XNA 图像查看器,但它总是重绘场景,即使它没有改变,而且它让我的上网本如地狱般燃烧,所以我希望它在没有任何变化时暂停绘图。

将帧速率降低到 1 是让它保持凉爽的一种方法,但它会导致输出延迟。

在没有输入的情况下如何防止重绘?


这个问题解决了,但又发现了另一个问题——当它的窗口处于焦点时,游戏会消耗大量的 CPU,而当它没有焦点时,它只占用大约 1% 的 CPU。有关如何解决其他问题的详细信息,请参阅此问题:

How to reduce XNA game CPU usage while nothing worth computing is happening?

【问题讨论】:

  • 这是一个快速的反对票和一个接近的投票。愿意帮助改进问题吗?
  • 如果人们离开 cmets 来解释他们的反对意见,那就太好了。这似乎是一个有明确答案的完全合理的问题。

标签: c# xna throttling


【解决方案1】:

您可以为此目的使用Game.SupressDraw 方法。从链接的评论中:

在 Update 期间调用此方法可防止在下次调用 Update 之前调用 Draw。如果显示没有因更新而改变,则此方法可用于小型设备以延长电池寿命。例如,如果屏幕是静态的,没有背景动画,则可以在更新期间检查玩家输入以确定玩家是否正在执行任何操作。如果未检测到输入,则此方法允许游戏跳过绘制直到下一次更新。

例如,以下代码只会调用一次Draw 函数。当我对此进行测试时,我注意到在没有 SuppressDraw 调用的情况下 CPU 使用率很高(70%)。使用SupressDraw 时,CPU 使用率急剧下降(低于 15%)。您的数字可能会有所不同。

public class Game1 : Microsoft.Xna.Framework.Game
{
    ...
    private bool _drawn = false;
    protected override void Update(GameTime gameTime)
    {
        if (_drawn)
            SuppressDraw();
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();
        /* draw stuff here */
        spriteBatch.End();

        _drawn = true;
    }
    ...
}

注意SupressDraw 只抑制一个Draw 调用。为了防止更多地调用Draw,您必须不断地在Update 中调用SupressDraw。希望这是有道理的。

【讨论】:

  • 这绝对有效,尽管它并没有像我希望的那样节省我的 CPU。性能分析表明,在抑制每个并条机后,主要更新方法得到了所有关注,但它仍然像以前一样消耗 CPU。我想问的问题已经回答了,但我仍然需要知道如何减少几乎什么都不做的 CPU 成本。
  • @user1306322 - 没有看到您的代码,很难回答为什么您的 CPU 使用率没有减少。正如您在上面的回答中看到的那样,它确实减少了我的示例程序的 CPU 时间 - 从 70% 的使用率降低到 15% 左右。
  • 如你所说——百分比不同。我猜 Draw 调用实际上并没有消耗任何大量资源,而整个应用程序正在使用尽可能多的资源(并且仍然如此)。所以基本上这变成了另一个问题——确定究竟是什么消耗了 CPU,而实际上除了等待输入和每秒绘制 60 次帧之外没有什么特别的事情发生。
【解决方案2】:

正如公认的答案所说,您可以使用 SuppressDraw 来避免绘制未更改的框架。不管怎样,你的更新方法都会运行,这就是为什么它仍然使用比你预期更多的 CPU。为了避免使用尽可能多的 CPU,您需要以某种方式避免更新您知道自上一帧以来没有更改的内容。

我假设您会像知道何时禁止绘制一样知道这一点,因此您需要做的是重新排列更新方法,如下所示:

private void Update(GameTime gameTime)
{
    var frameHasChanges = DetectChanges(); //This method you need to figure out yourself
    if (!frameHasChanges)
    {
        SuppressDraw();
        base.Update(gameTime);
        return;
    }

    //Do the rest of normal Update

}

作为最后一点;我从来没有在我做过的任何游戏中使用它。我觉得这表明您可能还有其他一些潜在的性能问题。但是,我使用了许多技术来避免在每一帧上渲染文本等(导致装箱/拆箱)。如果您想了解更多信息,请在评论中询问。

【讨论】:

  • 虽然一般来说这是要走的路,但在这种特殊情况下,正如我在问题中所说,更新方法非常简单,它不能仅仅为了检查是否存在而占用所有 CPU是输入状态的变化(它没有,我四次检查它)。解决方案是通过与解决此问题中的 no-redraw 事情后出现的问题不同的问题找到的。有关详细信息,请参阅问题脚注。
猜你喜欢
  • 1970-01-01
  • 2010-10-09
  • 2013-09-13
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
相关资源
最近更新 更多