优化 XNA 上的颜色操作

发布于 2024-08-15 13:40:41 字数 1050 浏览 1 评论 0原文

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

我需要每帧调用此方法 2000 次(对于地图上的每个图块),这为 XNA 的 60 fps 提供了每秒 120000 次的调用。即使单个调用的最小提升也会产生巨大的速度影响。但我只是不知道如何才能使其更有效

    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%

I am profiling my simple 2D XNA game. I found that 4% of entire running time is taken by simple operarion of adding together two Colors , one of them multiplied first by float.

I need to call this method rogulthy 2000 times per frame (for each tile on map), which gave me 120000 times per second for XNA's 60 fps. Even minimal boosting of single call whould give huge speed impact. Yet I simple do not know how can I make this more effective

    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));

    }

EDIT: As suggested by 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));
    }

This lowered time usage from 4% to 2.5%

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花开雨落又逢春i 2024-08-22 13:40:41

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

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% 吗?
那是很小
使用仅进行检测或对程序计数器进行采样的分析器的人们通常会对这样的小改进感到满意。
我敢打赌,你还有其他需要花费更多时间的事情正在发生,你可以攻击它们。 以下是我的意思的示例。

My first question is, why floating point? If you're just scaling colors to fade them, you don't need a lot of precision. Example:

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

In other words, represent your factor as an integer from 0 to 256, and do all the calculations on integers. You don't need more precision than 8 bits because the result is only 8 bits.

My second question is, did you say you went from 4% to 2.5% in this code?
That's tiny.
People who use profilers that only do instrumentation or sample the program counter are often satisfied with such small improvements.
I bet you have other things going on that take a lot more time, that you could attack. Here's an example of what I mean.

老子叫无熙 2024-08-22 13:40:41

明显的改进是在 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 通道,并且可能会稍微减少指令量。

The obvious improvement would be to include the division operation (/ 255) in the calculation of mul, to reduce the divisions from 3 to a single division:

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));
}

That being said, since you're replacing tile.Color, it may actually be faster to replace it in place instead of overwriting it (though I'd profile this to see if it helps):

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);
}

This prevents the recalculation of the alpha channel, and may reduce the amount of instructions a bit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文