Войти
ПрограммированиеПодсказкиГрафика

Быстрая аппроксимация инструкции RSQ

Автор:

Ускорения вычисления 1/sqrt(x) аппроксимацией

Для старых видеокарт вычисление 1/sqrt(x) инструкцией RSQ занимает
несколько драгоценных тактов в пиксельном шейдере, так для NV3x время
исполнения одной такой инструкции составлят 3 такта.

Наиболее часто RSQ используется для нормирования векторов H, N, L, и
потому является источником неэффективности шейдера. Для повышения
скорости приходится часть векторов нормировать с помощью кубических
текстур, но при этом напрасно расходуется часть пропускной способности
памяти.

Если векторы были нормированы перед передачей их в пиксельный шейдер, а
количество треугольников в модели велико, то скорее всего длина любого
интерполированного вектора будет в пределах [0.8; 1.0].

Эмпирически была выбрана квадратичная функция, которая двумя командами
MAD весьма точно аппроксимирует 1/sqrt(x) на отрезке [0.8; 1.0]:

    1/sqrt(x) = 1.99 + x * (0.5 * x - 1.49);

Пример реализации для GLSL:

vec3 Normalize( vec3 v )
{
    float r0 = dot( v, v );
    float r1 = 0.5 * r0 - 1.49;
    return (( r1 * r0 + 1.99 ) * v);
}

Пример реализации для ARBfp1.0:

   DP3  R0.x, vec, vec;
   MAD  R1.x, R0,  0.5, -1.49;
   MAD  R1.x, R0,  R1,   1.99;
   MUL  vec,  vec, R1.x;

Ну и самое важное: таким образом можно одновременно аппроксимировать
ЧЕТЫРЕ значения, если использовать все четыре компонента переменных
R0 и R1 :-))))  Пример реализации для ARBfp1.0:

   DP3  R0.x, vec1, vec1;
   DP3  R0.y, vec2, vec2;
   DP3  R0.z, vec3, vec3;
   DP3  R0.w, vec4, vec4;

   MAD  R1, R0, 0.5, -1.49;
   MAD  R1, R0, R1,   1.99;

   MUL  vec1, vec1, R1.x;
   MUL  vec2, vec2, R1.y;
   MUL  vec3, vec3, R1.z;
   MUL  vec4, vec4, R1.w;

#шейдеры, #оптимизация

12 октября 2009