Войти
ПрограммированиеФорумГрафика

Z-интерполяция (2 стр)

Страницы: 1 2
#15
22:15, 5 ноя. 2017

}:+()___ [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 .

>Кстати, хорошо видно, что "скалярные" операции на самом деле векторные с отключенной записью результата.
Несколько неочевидно. Т. е. это даст те же значения, что и в таблице, но их можно достичь и по-другому же. Джоули экономить.

#16
22:52, 5 ноя. 2017

}:+()___ [Smile]
В смысле, если у тебя есть источники/детали - делись, что-ли.

#17
23:48, 5 ноя. 2017

FordPerfect
> Совсем не очевидно. Перемножить 2x24 бита или 2x53 - довольно большая разница.
Вообще-то 4x24 и 2x53, что достаточно близко.

> возможно, характеристики асимптотики те же, что и для
Для того, чтобы из Wallace tree для перемножения 64x64 бита сделать 2 32x32 или 4 16x16, достаточно просто "перерезать" некоторые проводки, даже финальный сумматор трогать не надо.
Соответственно, логично использовать для этого общее железо, максимально переиспользуя железную логику.
В случае плавающей точки все сложнее, однако ядро — все тот же целочисленный умножитель.

> Несколько неочевидно. Т. е. это даст те же значения, что и в таблице, но их можно достичь и по-другому же. Джоули экономить.
Не, понятно, что можно аппаратно отключить другую половину ALU для экономии энергии (хотя я сомневаюсь, что это возможно с потактовой гранулярностью).
Важно, что с практической точки зрения другая половина по-любому простаивает, т. е. от режима условного исполнения по маске в AVX-512 или на GPU ничем принципиально не отличается.

#18
1:18, 6 ноя. 2017

}:+()___ [Smile]
> Для того, чтобы из Wallace tree для перемножения 64x64 бита сделать 2 32x32 или
> 4 16x16, достаточно просто "перерезать" некоторые проводки, даже финальный
> сумматор трогать не надо.
> Соответственно, логично использовать для этого общее железо, максимально
> переиспользуя железную логику.
обычно на современном железе, умножение делают через рекурсивный алгоритм деления пополам, (A_high*2^(N/2) + A_low)*(B_high*2^(N/2) + B_low)
в результате получаетcя схема с высоким темпом(за счет конвееризации каждого шага) и относительно небольшой задержкой.
соответсвенно посчитать более узкий результат - просто забрать его на предыдущем шаге пайплайна.

#19
3:59, 6 ноя. 2017

В общем без деления единицы никак не обойтись.
Шаг нелинейный получается.

#20
6:59, 6 ноя. 2017

thevlad
> обычно на современном железе, умножение делают через рекурсивный алгоритм деления пополам
Пруфы есть? А то я что-то сильно сомневаюсь, что в одном ALU сразу несколько умножителей.

eDmk
> В общем без деления единицы никак не обойтись.
Да, одно перспективное деление на пиксель необходимо для корректных текстурных координат.

> Шаг нелинейный получается.
А вот Z-буфферу на это параллельно, на настоящих GPU он нелинейный.

#21
12:10, 6 ноя. 2017

>на настоящих GPU он нелинейный
Так он везде нелинейный из-за перспективной матрицы.
Хотя в ортогональной проекции он скорее всего линейный.

#22
13:23, 6 ноя. 2017

Не знаю, что у тебя за компилятор, но Дельфи-7 ужасно оптимизирует вещественные операции, но неплохо оптимизирует целочисленные. Поэтому советую фиксированную запятую.
И да, тебе уже сказали, что величина 1/z меняется линейно, это значит, что тебе надо просто вычислить rev_z0 и d_rev_z.
И достаточно писать в з-буфер только 1/z, делать деление нафиг не надо.
Деление нужно лишь для перспективной коррекции текстур, но и там можно считерить, например, сб3д забил на перспективную коррекцию, сделал мелкие полигоны и на них не видно, как текстура "едет".

#23
13:36, 6 ноя. 2017

> 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 одним сложением при движении по полосе пикселей.

#24
13:54, 6 ноя. 2017

>Не знаю, что у тебя за компилятор, но Дельфи-7 ужасно оптимизирует вещественные операции
RAD Delphi XE6 Prof. Оптимизация жуткая. Почти бесполезная. Масимум 0.5-1% добавляет по скорости.
Я выравнивание никак не могу включить в Delphi. Из-за этого команды movaps или movdqa в ассемблере недоступны.
Везде невыровненные данные через movdqu. Может и от этого тормозит.

#25
14:25, 6 ноя. 2017

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-буфер нету, глубина используется лишь для тумана.

Прошло более 9 месяцев
#26
12:25, 17 авг. 2018

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.
Тогда ваш вариант подходит.

#27
13:47, 17 авг. 2018

}:+()___ [Smile]
> Кстати, хорошо видно, что "скалярные" операции на самом деле векторные с
> отключенной записью результата.
ну это же компилятор их превратил в SSE-команды?

Страницы: 1 2
ПрограммированиеФорумГрафика

Тема в архиве.