Оптимизация цветовых манипуляций на XNA - PullRequest
5 голосов
/ 18 декабря 2009

Я профилирую свою простую 2D игру XNA. Я обнаружил, что 4% всего времени выполнения занято простой операцией сложения двух цветов, один из которых умножается сначала на число с плавающей запятой.

Мне нужно вызывать этот метод 2000 раз за кадр (для каждой плитки на карте), что дало мне 120000 раз в секунду для 60 кадров в секунду в XNA. Даже минимальное усиление одного звонка дало бы огромное влияние на скорость. Все же я просто не знаю, как я могу сделать это более эффективным

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

    }

РЕДАКТИРОВАТЬ: В соответствии с предложением Майкла Стум:

    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%

Ответы [ 2 ]

1 голос
/ 18 декабря 2009

Мой первый вопрос: почему с плавающей точкой? Если вы просто масштабируете цвета, чтобы затушить их, вам не нужно много точности. Пример:

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% в этом коде? Это крошечный . Люди, которые используют профилировщики, которые только выполняют инструментарий или пробуют счетчик программ, часто довольны такими небольшими улучшениями. Бьюсь об заклад, у вас есть другие вещи, которые занимают гораздо больше времени, что вы могли бы атаковать. Вот пример того, что я имею в виду.

1 голос
/ 18 декабря 2009

Очевидным улучшением было бы включение операции деления (/ 255) в вычисление mul, чтобы уменьшить деления с 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);
}

Это предотвращает пересчет альфа-канала и может немного уменьшить количество инструкций.

...