· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.A&O —› mmx alpha blending

Посл.отвђт Сообщенiе


Дата: Апр 4, 2004 00:34:50

Всем Hi! Кто-нить писал альфа-блендинг двух битмэпов с исп. MMX???
У меня процедура смешивает 2а разных по размеру битмэпа, имеющих разные форматы следования цветов (32бит). Пример - 1) 400x300@RGBA; 2) 500x400@BRAG
<< т.е. - На лету конвертится из 2) в 1) >>
Также указывается точка X,Y - коорд. на Destination битмэпе, обозначающие верх.левый угол Source битмэпа, куда происходит копирование.
Получаю такой реультат (P3-733Mhz):

Source bitmap: 400x300
Destination bitmap: 400x300 (X,Y)=(0,0) - копируем весь Source
~65 FPS

Неужели это максимум скорости на MMX??? Почему AlphaBlend() дает ~450 FPS ????

Привожу основной цикл:
<...>
__start://переводим формат пикселей Source в формат Dest
mov edx,dword ptr[esi]; //eax=SrcPixel
ror edx,cl;
mov ah,dl;
ror ecx,8;
ror edx,cl;
mov al,dl;
ror ecx,8;
rol eax,16;
ror edx,cl;
mov ah,dl;
ror ecx,8;
ror edx,cl;
mov al,dl;
ror ecx,8;

//готовим регистры
pxor mm7,mm7; //mm7=zero
xchg ecx,ebx; //get alpha
movd mm0,eax; //mm0=SrcPixel (converted to DstPixel format)
ror ecx,16;
punpcklbw mm0,mm7;

ror eax,cl;
mov ah,al; //eax={alpha alpha alpha alpha}
mov dx,ax;
bswap eax;
mov ax,dx;
movd mm4,eax; //mm4={0 0 0 0 alpha alpha alpha alpha}
mov edx,dword ptr[edi]; //eax=DstPixel
punpcklbw mm4,mm7; //mm4={0 alpha 0 alpha 0 alpha 0 alpha}
mov eax,edx;
psllw mm4,4; //сдвигаем mm4 (требо для pmullw)

movd mm1,eax; //mm1=DstPixel
ror edx,cl;
punpcklbw mm1,mm7;
psubw mm0,mm1; //SrcPixel - DstPixel (со знаком)
psllw mm0,4; //low word to high word
pmulhw mm0,mm4; //mm0 * alpha
add esi,4;
paddw mm1,mm0; //mm1 + SrcPixel * alpha
packuswb mm1,mm1; //32 bit result
movd eax,mm1;
ror eax,cl;
mov al,dl; //копируем Dst alpha в результат
rol eax,cl;
ror ecx,16;
mov dword ptr[edi],eax; //copy result to DstPixel
xchg ecx,ebx;

//проверки на Out Of Range
add edi,4;
dec bx; //next line?
jnz __start;
<...>


Дата: Апр 4, 2004 12:50:57 · Поправил: Black_mirror

PowerE

Вот мой не MMX вариант:
blend:;(src +4, dest +8, width +12, height +16)
	xchg esi,[esp+4]	;Src[] Sr Sg Sb Sa
	xchg edi,[esp+8]	;Dst[] Dr Dg Db Da
	push ebx
	push ebp	;+8
    .l0:
	push dword [8+esp+12]
    .l1:
	movzx ebx,byte [esi+3]	;Sa
	movzx eax,byte [esi+1]	;Sg
	shl eax,16
	mov al,[esi+0]		;Sg|Sr
	mul ebx			;eax=Sg*Sa|Sr*Sa
	mov ecx,eax
	movzx eax,byte [edi+1]	;Dg
	not bl			;1-Sa
	mov al,[edi+0]		;Dg|Dr
	mul ebx			;eax=Dg*(1-Sa)|Dr*(1-Sa)
	add ecx,eax		;ecx=Sg*Sa+Dg*(1-Sa)|Sr*Sa+Dr*(1-Sa)
	mov [edi+0],ch		;Sr*Sa+Dr*(1-Sa)
	bswap ecx
	mov [edi+1],cl		;Sg*Sa+Dg*(1-Sa)
	movzx eax,byte [esi+3]	;Sa
	movzx eax,byte [edi+3]	;Da
	shl eax,16
	mov al,[edi+2]		;Da|Db
	mul ebx			;eax=Da*(1-Sa)|Db*(1-Sa)
	mov ecx,eax
	not bl			;Sa
	shl eax,16
	mov al,[esi+2]		;Sa|Sb
	mul ebx			;eax=Sa*Sa|Sb*Sa
	add ecx,eax		;ecx=Sa*Sa+Da*(1-Sa)|Sb*Sa+Db*(1-Sa)
	mov [edi+2],ch		;Sb*Sa+Db*(1-Sa)
	bswap ecx
	mov [edi+3],cl		;Sa*Sa+Da*(1-Sa)
	add esi,4
	add edi,4
	dec dword [esp]
	jnz .l1
	add esp,4
	dec dword [8+esp+16]
	jnz .l0
	pop ebp
	pop ebx
	mov esi,[esp+4]
	mov edi,[esp+4]
	ret 16

Протестируй его пожалуйста на своей системе. А то на атлоне получается 28 тактов на пиксель.

PS: В коде был баг и он исправлен, но на производительность это никак не повлияло.


Дата: Апр 4, 2004 13:17:36

Это все IMHO.
Так что не воспринимайте слишком серьезно ;-)

Почему AlphaBlend() дает ~450 FPS ????
Используется аппаратное ускорение, на больших битмапах это быстрее, чем CPU.


Если желание заниматься этим не пропало, т.е. вы будете использовать для копирования множества маленьких битмапов, то:

Для начала, все нужно хранить в одном формате.
Конверсия "на лету" - серьезный bottleneck.

Даже абстракционист Вирт пишет, что программы=алгоритмы+структуры данных
На асме нам и карты в руки :)


Далее, что такое alpha blending? Не что иное, как копирование памяти, с некоторым преобразованием.
Техника оптимизации таких действий описана тут (английский, но из листингов принципы понятны)


У вас P3 (SD-RAM). Т.е. при хорошем раскладе, можно получить (полностью програмную) скорость перерисовки экрана 800*600*32 - как минимум в 2 раза выше, чем частота развертки монитора.


Дата: Апр 4, 2004 14:14:34

S_T_A_S_
По моему 150 FPS ну никак не получить. У меня MMX вариант выигрывает у не MMX всего на 15 процентов.


Дата: Апр 4, 2004 14:40:53

Black_mirror
IMHO все зависит от конкретного случая, а не от общего

Я именно таким альфа-наложением не занимался, несколько другие варианты были, но думаю можно.
Оптимизировать надо не только сам внутренний цикл.

Для начала меняем формат хранения поверхности:
XX A*R A*G A*B - размер source удваивается, зато нет лишних вычислений (!)

Используем movntq (это уже SSE) для записи минуя кеш.
И сами опреации надо строить с учетом кеша, т.е обрабатывать блоками (как в том ^^ PDF)

В общем-то у меня обычно все в пропускную способность памяти упирается - она заметно меньше, чем скорость ядра.
Если нет - значит надо что-то серьезно менять в другом месте.

А в этом случае (400x300@RGBA) - может действительно не заморачиваться, а юзать hardware?
(хотя я его и не люблю :D)


Дата: Апр 5, 2004 20:11:39

Black_mirror
Я сохранил ваш код, когда приступлю к аналогичной процедуре на cpu, протестирую... но думаю не скоро, недели через две. или приведите полную процедуру (в виде C++ + __asm), чтоб мне не возится с этим.
S_T_A_S_
У меня есть набор процедур для каждого случая (одинаковые форматы, без аьфы и т.д.). под SSE я буду оптимизировать в процедуре с SSE (кстати, с преобразованием формата там как раз рай! одной командой! не помню к сожалению какой именно), а тут у меня обычный MMX.
Единственное я понял: особой ошибки в алгоритме у меня нет, т.к. вы бы сразу закритиковали код:). Значит так оно и должно быть (+/- o(N) fps).
Начсет - A*R A*G A*B, тут не подходит, процедуру общего характера, все стандартные поверхности за исключением формата RGBA.


Дата: Апр 6, 2004 13:42:37

PowerE

movntq - это "не совсем SSE" . Это расширение MMX (movq), но нет засорения кеша - поэтому скорость будет выше.
Проц не будет читать данные из памяти (как при обычной записи) перед тем как туда записать что-то новое.

Единственное я понял: особой ошибки в алгоритме у меня нет, т.к. вы бы сразу закритиковали код:)
Если нет времени читать Фога, рекомендую все же посмотреть тот PDF, там кратко приведены примеры оптимизации.

процедуру общего характера

IMHO есть 2 совершенно разных варианта: унивирсальность или скорость.
Собственно поэтому у меня и нет готового кода для вашего случая.


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.059