}:+()___ [Smile]
>Скорее всего, выполняется на общем железе для float/double (а возможно и для целых), непонятно откуда там дополнительная задержка.
Совсем не очевидно. Перемножить 2x24 бита или 2x53 - довольно большая разница.
Я хз, что в Core i7, но, возможно, характеристики асимптотики те же, что и для https://en.wikipedia.org/wiki/Wallace_tree , https://en.wikipedia.org/wiki/Adder_%28electronics%29#Adders_supp… multiple_bits .
>Кстати, хорошо видно, что "скалярные" операции на самом деле векторные с отключенной записью результата.
Несколько неочевидно. Т. е. это даст те же значения, что и в таблице, но их можно достичь и по-другому же. Джоули экономить.
}:+()___ [Smile]
В смысле, если у тебя есть источники/детали - делись, что-ли.
FordPerfect
> Совсем не очевидно. Перемножить 2x24 бита или 2x53 - довольно большая разница.
Вообще-то 4x24 и 2x53, что достаточно близко.
> возможно, характеристики асимптотики те же, что и для
Для того, чтобы из Wallace tree для перемножения 64x64 бита сделать 2 32x32 или 4 16x16, достаточно просто "перерезать" некоторые проводки, даже финальный сумматор трогать не надо.
Соответственно, логично использовать для этого общее железо, максимально переиспользуя железную логику.
В случае плавающей точки все сложнее, однако ядро — все тот же целочисленный умножитель.
> Несколько неочевидно. Т. е. это даст те же значения, что и в таблице, но их можно достичь и по-другому же. Джоули экономить.
Не, понятно, что можно аппаратно отключить другую половину ALU для экономии энергии (хотя я сомневаюсь, что это возможно с потактовой гранулярностью).
Важно, что с практической точки зрения другая половина по-любому простаивает, т. е. от режима условного исполнения по маске в AVX-512 или на GPU ничем принципиально не отличается.
}:+()___ [Smile]
> Для того, чтобы из Wallace tree для перемножения 64x64 бита сделать 2 32x32 или
> 4 16x16, достаточно просто "перерезать" некоторые проводки, даже финальный
> сумматор трогать не надо.
> Соответственно, логично использовать для этого общее железо, максимально
> переиспользуя железную логику.
обычно на современном железе, умножение делают через рекурсивный алгоритм деления пополам, (A_high*2^(N/2) + A_low)*(B_high*2^(N/2) + B_low)
в результате получаетcя схема с высоким темпом(за счет конвееризации каждого шага) и относительно небольшой задержкой.
соответсвенно посчитать более узкий результат - просто забрать его на предыдущем шаге пайплайна.
В общем без деления единицы никак не обойтись.
Шаг нелинейный получается.
thevlad
> обычно на современном железе, умножение делают через рекурсивный алгоритм деления пополам
Пруфы есть? А то я что-то сильно сомневаюсь, что в одном ALU сразу несколько умножителей.
eDmk
> В общем без деления единицы никак не обойтись.
Да, одно перспективное деление на пиксель необходимо для корректных текстурных координат.
> Шаг нелинейный получается.
А вот Z-буфферу на это параллельно, на настоящих GPU он нелинейный.
>на настоящих GPU он нелинейный
Так он везде нелинейный из-за перспективной матрицы.
Хотя в ортогональной проекции он скорее всего линейный.
Не знаю, что у тебя за компилятор, но Дельфи-7 ужасно оптимизирует вещественные операции, но неплохо оптимизирует целочисленные. Поэтому советую фиксированную запятую.
И да, тебе уже сказали, что величина 1/z меняется линейно, это значит, что тебе надо просто вычислить rev_z0 и d_rev_z.
И достаточно писать в з-буфер только 1/z, делать деление нафиг не надо.
Деление нужно лишь для перспективной коррекции текстур, но и там можно считерить, например, сб3д забил на перспективную коррекцию, сделал мелкие полигоны и на них не видно, как текстура "едет".
> Z := 1.0 / (Pt.X * Z.X + Pt.Y * Z.Y + Pt.Z * Z.Z);
Тут барицентрические координаты не реальной точки реального треугольника, а проекции точки на экране относительно проекции треугольника на экране. Это значит, что при движении вдоль линии пикселей знаменатель меняется линейно.
Тебе перед началом движения по линии нужно узнать Pt0 - координаты начальной точки и dPt - на сколько меняются все координаты при смещении на соседний пиксель.
Того имеем формулу:
Z := 1.0 / (Pt.X * Z.X + Pt.Y * Z.Y + Pt.Z * Z.Z); W := Pt.X * Z.X + Pt.Y * Z.Y + Pt.Z * Z.Z; W0 := Pt0.X * Z.X + Pt0.Y * Z.Y + Pt0.Z * Z.Z; dW := dPt.X * Z.X + dPt.Y * Z.Y + dPt.Z * Z.Z;
Этих данных достаточно, чтоб интерполировать W одним сложением при движении по полосе пикселей.
>Не знаю, что у тебя за компилятор, но Дельфи-7 ужасно оптимизирует вещественные операции
RAD Delphi XE6 Prof. Оптимизация жуткая. Почти бесполезная. Масимум 0.5-1% добавляет по скорости.
Я выравнивание никак не могу включить в Delphi. Из-за этого команды movaps или movdqa в ассемблере недоступны.
Везде невыровненные данные через movdqu. Может и от этого тормозит.
eDmk
В Дельфи-7 фигач))) Только всё в целые числа 16:16 перегоняй перед сложными вещами по формуле round(x*65536.0). Например было 1.5 вещественное, будет 0x18000 целое.
И во внутреннем цикле чтоб никаких round() и вообще вызовов других функций. Внутренний цикл должен быть простой, как лопата.
procedure LoopNoDith (Px : PScreenColor; w, dw :integer; Pixels : PAColor; cnt : integer; tx,dtx,ty,dty,mx,my,sx : integer); var i : integer; begin for i := 0 to cnt-1 do begin Px^ := FogTable[w shr 16, Pixels[ ( ( tx shr 16)and mx) + ( ( ty shr 16)and my) shl sx ] ]; Inc( tx,dtx); Inc( ty,dty); Inc( w, dw); Inc( Px); end; end;
Px^ - экранный буфер, Pixels - текстура, w - величина, обратная глубине. В этом цикле записи в z-буфер нету, глубина используется лишь для тумана.
1 frag / 2 deaths
> Только всё в целые числа 16:16 перегоняй перед сложными вещами по формуле
> round(x*65536.0).
Ерунда получается.
Вот пример:
Число 15.5. Шаг — единица 1.0.
Гоним по вашей формуле:
Число: 15,5 * 65536 = 1015808
Шаг: 1,0 * 65536 = 65536
Расчет float:
15.5-1.0 = 14.5.
Round(14.5) = 15!!!
Расчет сдвигом:
1015808 - 65536 = 950272
950272 shr или >> 16 = 14!!!
Итого:
14 <> 15!!!!!!!!!!!
Единственный вариант возможен если нужен Trunc, а не Round.
Тогда ваш вариант подходит.
}:+()___ [Smile]
> Кстати, хорошо видно, что "скалярные" операции на самом деле векторные с
> отключенной записью результата.
ну это же компилятор их превратил в SSE-команды?
Тема в архиве.