|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Окт 8, 2003 20:02:31 Max проверить находится ли точка внутри треугольника с использованием SSE2 можно следующим образом:
struc triangle
{
.x1 dd ?
.x2 dd ?
.x3 dd ?
.y1 dd ?
.y2 dd ?
.y3 dd ?
}
test_pt:;(ptriangle +4,x +8,y +12)
;zf=1 если точка внутри треугольника
;и zf=0 в противном случае
mov edx,[esp+4];ptriangle
movd xmm0,[esp+8];|0|0|0|x|
movd xmm1,[esp+12];|0|0|0|y|
movdqu xmm2,[edx+triangle.x1];|U|x3|x2|x1|
movdqu xmm3,[edx+triangle.y1];|U|y3|y2|y1|
pshufd xmm0,xmm0,0;|x|x|x|x|
pshufd xmm1,xmm1,0;|y|y|y|y|
pshufd xmm4,xmm2,00001001b;|U|x1|x3|x2|
pshufd xmm5,xmm3,00001001b;|U|y1|y3|y2|
subps xmm4,xmm2;|U|x1-x3|x3-x2|x2-x1|
subps xmm5,xmm3;|U|y1-y3|y3-y2|y2-y1|
subps xmm1,xmm3;|U|y-y3|y-y2|y-y1|
subps xmm0,xmm2;|U|x-x3|x-x2|x-x1|
mulps xmm0,xmm5;|U|(x-x3)*(y1-y3)|(x-x2)*(y3-y2)|(x-x1)*(y2-y1)|
mulps xmm1,xmm4;|U|(y-y3)*(x1-x3)|(y-y2)*(x3-x2)|(y-y1)*(x2-x1)|
subps xmm0,xmm1;|U|d3|d2|d1|
pmovmskb eax,xmm0;Это единственная команда SSE2.
;Чем бы ее заменить, чтобы и на атлонах работало?
and eax,111h;проверяем знаки
jz .exit
xor eax,111h
.exit:
ret 12
|
|
|
Дата: Окт 9, 2003 13:36:29 Black_mirror Вот спасибо, процесс пошел... :) Сначала вопрос... movdqu загружает "Unaligned Double Quadword". Ничего, если ею загружается 4 single, а не 2 double? То есть получается, что процу пофиг что загружать? а теперь немного критики с моей стороны: 1. по условию задачи входные данные - это longint, т.е. их надо сначала преобразовывать к вещественному типу. Здесь же вычисления с ними ведутся как будто они single 2. опять же по условию, вычисления надо вести в double, тут все в single. 3. и опять же по условию :), если точка лежит на ребре она считается принадлежащей треугольнику. Здесь может получится d1=0, d2<0, d3<0, т.е. такой вариант не проверяется. Кстати, может получится d1=-0 (100..0B), d2>0, d3>0 - такой вариант не проверяется и в моем примере тоже, баг типа. |
|
|
Дата: Окт 9, 2003 17:43:21 По моему эта инструкция просто пересылает 128 бит из памяти в регист или наоборот. А как они будут трактоваться это будет зависить от того, что мы с ними делаем. Для такой задачи делать вычисления в double по моему не рационально. У нас всего 15(возможно 18) вычитаний и 6 умножений + проверка на знаки. Возможно что быстрее это на процессоре посчитать. |
|
|
Дата: Окт 9, 2003 19:38:06 То есть получается, SSE эффективно только для обработки чисел небольшой размерности, типа 16 байт, 4 сингла...? Может оно просто с double так погано работает? |
|
|
Дата: Окт 10, 2003 12:03:22 Не думаю что SSE не эффективно использовать для double. Всетаки мы обрабатываем сразу по два числа, а не по одному на сопроцессоре. Но если входные данные int32 то зачем использовать большую точность? На моем процессоре целочисленное умножение выполняется 5 тактов. То есть вычислить значения d1-d3 можно за 6*5+18/2=39 тактов. Плюс 10 тактов на проверку знаков. Итого 50 тактов. В вашем коде SSE комманд я насчитал 39 штук. Насколько я знаю, спариваются они очень плохо. Можно узнать какова частота вашего процессора, и сколько треугольников вы обрабатывали для тестирования производительности, а то мс мало о чем говорят. |
|
|
Дата: Окт 10, 2003 13:58:48 Вот вариант без SSE:
struc tria
{
.x1 dd ?
.x2 dd ?
.x3 dd ?
.y1 dd ?
.y2 dd ?
.y3 dd ?
}
ptin:;(ptria +4, x +8, y +12)
virtual at ebx
.t tria
end virtual
xor ebp,ebp;здесь будут суммироваться знаки
mov ebx,[esp+4]
;вычисление d
mov edx,[esp+12]
mov eax,[.t.x2]
sub edx,[.t.y1]
sub eax,[.t.x1]
mov ecx,[esp+8]
imul edx
sub ecx,[.t.x1]
mov esi,eax
mov eax,[.t.y2]
mov edi,edx
sub eax,[.t.y1]
imul ecx
sub eax,esi
sbb edx,edi
;проверка знака
shl edx,1
sbb ebp,0
or eax,edx
setnz cl
add ebp,ecx
mov edx,[esp+12]
mov eax,[.t.x3]
sub edx,[.t.y2]
sub eax,[.t.x2]
mov ecx,[esp+8]
imul edx
sub ecx,[.t.x2]
mov esi,eax
mov eax,[.t.y3]
mov edi,edx
sub eax,[.t.y2]
imul ecx
sub eax,esi
sbb edx,edi
shl edx,1
sbb ebp,0
or eax,edx
setnz cl
add ebp,ecx
mov edx,[esp+12]
mov eax,[.t.x1]
sub edx,[.t.y3]
sub eax,[.t.x3]
mov ecx,[esp+8]
imul edx
sub ecx,[.t.x3]
mov esi,eax
mov eax,[.t.y1]
mov edi,edx
sub eax,[.t.y3]
imul ecx
sub eax,esi
sbb edx,edi
shl edx,1
sbb ebp,0
or eax,edx
setnz cl
add ebp,ecx
xor eax,eax
test ebp,3
jnp .exit
inc eax
.exit:
ret 12
Если длина стороны больше 2^31-1 будет работать некорректно. На Athlon1900+ работает примерно за 60 тактов, вместе с кодом для вызова. Проверки на знаки нужно делать по другому, а то там сильная зависимость по данным. (Только вот как?) Возвращает eax=1 если точка попадает внутрь треугольника, и eax=0 если не попадает или попадает на сторону. |
|
|
Дата: Окт 10, 2003 16:22:07 · Поправил: Max Black_mirror Но если входные данные int32 то зачем использовать большую точность? Дело в том, что там используется перемножение. Если int32 * int32, то результат должет быть int64, иначе рискуем получить неверный результат (точнее правильный, но по модулю). Поэтому сравнивать мой пример с твоим строго говоря нельзя - они делают разные вещи. Можно узнать какова частота вашего процессора, и сколько треугольников вы обрабатывали для тестирования производительности, а то мс мало о чем говорят. Это я прогонял на P4 2.4GHz, DDR 512Mb 533MHz [added: треугольников 1Е6] |
|
|
Дата: Окт 10, 2003 17:01:23 Max После умножения у нас три пары 64-битных чисел. И нужно сделать всего три 64-битных вычитания. В моем коде так и делается. Единственный случай когда программа выдает некорректный результат, это если длина проекции стороны треугольника на X или Y больше 2^31-1. Замеры производительности для 1E6 треугольников кода без SSE, показали что требуется 92 такта на треугольник. Примерно 58 ms. И 38 ms если данные помещаются в кеше. То есть все дело в пропускной способности памяти или шины. Ваш вариант с сопроцессором тратит 84 такта на треугольник. Похоже дело в том что умножение чисел с плавающей точкой выполняется быстрее чем целочисленное. Или в том что частота памяти у меня в 2 раза меньше 8) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.075 |