【问题标题】:Optimize color manipulation on XNA优化 XNA 上的颜色处理
【发布时间】:2010-12-28 03:15:48
【问题描述】:

我正在分析我的简单 2D XNA 游戏。我发现整个运行时间的 4% 是通过将两个 Colors 相加的简单操作占用的,其中一个先乘以 float。

我需要每帧调用这个方法 rogulthy 2000 次(对于地图上的每个图块),这给了我每秒 120000 次 XNA 的 60 fps。即使是单个呼叫的最小提升也会产生巨大的速度影响。然而我只是不知道我怎样才能使它更有效

    private void DoColorCalcs(float factor, Color color)
    {
        int mul = (int)Math.Max(Math.Min(factor * 255.0, 255.0), 0.0);
        tile.Color = new Color(
            (byte)Math.Min(tile.Color.R + (color.R * mul / 255), 255),
            (byte)Math.Min(tile.Color.G + (color.G * mul / 255), 255),
            (byte)Math.Min(tile.Color.B + (color.B * mul / 255), 255));

    }

编辑:正如 Michael Stum 所建议的:

    private void DoColorCalcs(float factor, Color color)
    {
        factor= (float)Math.Max(factor, 0.0);
        tile.Color = new Color(
            (byte)Math.Min(tile.Color.R + (color.R * factor), 255),
            (byte)Math.Min(tile.Color.G + (color.G * factor), 255),
            (byte)Math.Min(tile.Color.B + (color.B * factor), 255));
    }

这将时间使用率从 4% 降低到 2.5%

【问题讨论】:

  • 您要查找的词是优化,而不是优化。 :)
  • 听起来很多人都在呼吁一个简单的 2D 游戏。你不能改变整体算法吗?通过例如缓存结果还是避免每帧都做所有事情?
  • 我需要重新计算图块的动态光(我的照明模型包括光闪烁,它会以 Sin(time)*0.1 的速率改变每帧中给定图块的光强度)
  • 您是否需要提高效率?现在的表现真的有问题吗?你刚才说它只需要总执行时间的 4%。这意味着您的“巨大”速度影响最多将是 4%。这意味着您的应用可能以 62.4 FPS 而不是 60 FPS 运行。这真的值得付出努力吗?
  • 您可以尝试将您的图块分成 2 (4, 8) 个组并创建多个线程 - 每个线程计算一个图块组的颜色。因此,您可以使用您的处理器提供的所有内核。

标签: c# optimization profiling xna


【解决方案1】:

明显的改进是在mul的计算中加入除法运算(/255),将除法从3减少到单除:

private void DoColorCalcs(float factor, Color color)
{
    float mul = Math.Max(Math.Min(factor * 255.0f, 255.0f), 0.0f) / 255f; 
    tile.Color = new Color(
        (byte)Math.Min(tile.Color.R + (color.R * mul), 255),
        (byte)Math.Min(tile.Color.G + (color.G * mul), 255),
        (byte)Math.Min(tile.Color.B + (color.B * mul), 255));
}

话虽如此,由于您要替换 tile.Color,实际上替换它而不是覆盖它可能会更快(尽管我会对此进行分析以查看它是否有帮助):

private void DoColorCalcs(float factor, Color color)
{
    float mul = Math.Max(Math.Min(factor * 255.0f, 255.0f), 0.0f) / 255f;
    tile.Color.R = (byte)Math.Min(tile.Color.R + (color.R * mul), 255);
    tile.Color.G = (byte)Math.Min(tile.Color.G + (color.G * mul), 255);
    tile.Color.B = (byte)Math.Min(tile.Color.B + (color.B * mul), 255);
}

这可以防止重新计算 Alpha 通道,并且可能会稍微减少指令量。

【讨论】:

  • (int)Math.Max(Math.Min(factor * 255.0, 255.0), 0.0) / 255 在大多数情况下将导致 0。所以这没有帮助。
  • 同意 Simon Ottenhaus - 你将整数 0..255 除以 255,得到 254 个零和单个值“一”
  • 啊,我忘了 - 我试图通过设置它的变量来替换创建新的 Color 对象。它需要一些“坏方法”,因为我必须将 tile.Color 从 Accessor 类型更改为 Variable。但它仍然没有速度影响(测试和四舍五入到 0,1 fps)
  • 那你不能把 mul 改成浮点数吗?还是说太不准确了?
  • 你可以这样做,但你必须让 mul 成为一个浮点数。由于您在所有其他计算中都在进行基于浮点数的数学运算,因此实际上应该会稍微提高速度。
【解决方案2】:

我的第一个问题是,为什么是浮点数?如果您只是缩放颜色以使它们褪色,则不需要很高的精度。示例:

int factorTimes256;
tile.Color.R = Math.Max(255, tile.Color.R + (color.R * factorTimes256) / 256);
// same for G and B

换句话说,将您的因子表示为从 0 到 256 的整数,并对整数进行所有计算。您不需要超过 8 位的精度,因为结果只有 8 位。

我的第二个问题是,你是说你在这段代码中从 4% 变为 2.5% 吗? 那是很小。 使用仅进行检测或对程序计数器进行采样的分析器的人通常对如此小的改进感到满意。 我敢打赌,您还有其他需要花费更多时间的事情发生,您可能会发起攻击。 Here's an example of what I mean.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 2011-02-07
    • 2012-11-02
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 2011-04-12
    相关资源
    最近更新 更多