Эффективная реализация декомпрессии текстуры DXT1 в аппаратном обеспечении
Сжатие DXT1 разработано для быстрой распаковки на оборудовании, где оно используется в сэмплерах текстуры. В статье Википедии говорится, что при определенных обстоятельствах вы можете определить коэффициенты интерполированных цветов как:
c2 = (2/3)*c0+(1/3)*c1
или переставить это:
c2 = (1/3)*(2*c0+c1)
Однако, если вы переставите вышеприведенное уравнение, то вам всегда придется умножать что-то на 1/3 (или делить на 3, такая же сделка еще дороже). И мне кажется странным, что формат текстуры, который разработан для быстрой распаковки в аппаратном обеспечении, потребует умножения или деления. FPGA, на которой я использую свой GPU, имеет ограниченные ресурсы для умножения, и я хочу сохранить их там, где они действительно необходимы.
Так я что-то упустил? Есть ли эффективный способ избежать умножения цветовых каналов на 1/3? Или я должен просто съесть стоимость этого умножения?
2 ответа
Это могло бы быть плохим способом представить это, но могли бы вы реализовать это с помощью сложения / вычитания последовательных половинок (сдвигов)?
Поскольку у вас есть 16 битов, это дает вам возможность получить довольно точные данные с последовательными сложениями и вычитаниями.
Третий может быть представлен как
a(n+1) = a(n) +/- A>>1, где список [0, 0, 1, 0, 1 и т. д.] показывает, следует ли сложить или вычесть смещенный результат.
Я считаю, что это называется дробной математикой.
Однако в FPGA трудно понять, является ли это на самом деле более энергоэффективным, чем предоставленные собственные блоки DSP (например, DSP48E1).
Мой лучший ответ, который я могу придумать, это то, что я могу использовать личность:
x/3 = sum(n=1 to infinity) (x/2^(2n))
а затем возьмите первые n членов. Используя 4 условия, я получаю:
(x/4)+(x/16)+(x/64)+(x/256)
который равен
x*0.33203125
что, вероятно, достаточно хорошо.
Это зависит от умножения на фиксированную степень 2, которая является бесплатной в аппаратном обеспечении, затем 3 дополнения, из которых я могу запустить 2 параллельно.
Любой лучший ответ приветствуется.
** РЕДАКТИРОВАТЬ **: Используя комбинацию этого и ответа @dyslexicgruffalo, я создал простую программу на C++, которая перебирала различные последовательности, пробовала их все и записывала различные средние / максимальные ошибки.
Я сделал это для 0 <= x <= 189 (так как 189 - это значение 2*c0.g + c1.g, когда g (то есть 6 битов) достигает максимума.
Самая короткая хорошая последовательность (с максимальной ошибкой 2, средней ошибкой 0,62) и 4 операциями была:
1 + x/4 + x/16 + x/64.
Лучшая последовательность с максимальной ошибкой 1, средней ошибкой 0,32, но с 6 операциями была:
x/2 - x/4 + x/8 - x/16 + x/32 - x/64.
Для 5-битных значений (красного и синего) максимальное значение составляет 31*3, и приведенные выше последовательности все еще хороши, но не являются лучшими. Это:
x/4 + x/8 - x/16 + x/32 [max error of 1, average 0.38]
а также
1 + x/4 + x/16 [max error of 2, average of 0.68]
(И, к счастью, ни одна из вышеперечисленных последовательностей никогда не угадывает ответ, который является слишком большим, поэтому зажим не требуется, даже если они не идеальны)