-
Название темы дурацкое, поясню чего я хотел :) Пишу блитинг битмапов методом сложения (высветления, сверху накладывается спрайт огня или дыма без альфы нарисованный на черном фоне, а на бекграунде каждый пиксель спрайта складывается и получается высветленная область (PS в стиле "Капитана Очевидность", но мало ли...:) )), с оптимизацией на ММХ. В данный момент есть код просто и без затей выполняющий сложение: movq mm0, [edi] movq mm1, [edi+8]
paddusb mm0, [esi] paddusb mm1, [esi+8]
movq [edi], mm0 movq [edi+8], mm1
add esi, edx add edi, edx Дикая производительность радует. Но понадобилось теперь выводить спрайт с различной степенью прозрачности, причем не только меньше 100%, но и с превышением (будет засветка спрайта), причем делать это нужно уже на выводе. Так вот вопрос - помогите написать это умножение :) Регистры ММХ все свободны, eax занят. В принципе полупрозрачность я реализую, но вот как сделать пересвет (прозрачность на 250%) я не пойму :( ЗЫ и, походу, в умножении нет такой замечательной функции как рaddusb, с самопроверкой на переполнение :(
-
чуть позже выложу тестовый проект
-
-
Битмап забыл в пример положить :) Ну ладно, я вроде и так понял, что нужно такое: DstColor := DstColor + SrcColor * Alpha где Alpha может быть > 1.0 (или 255, если в целых)
Проблема с MMX-умножением в том, что "вершки" (старшие разряды для всего что больше 65535) мы получаем в одном регистре (командой PMULHW), а "корешки" - в другом (PMULLW). Если ты будешь использовать коэфф. больше 255, у тебя естественно может получиться больше 65535. Как обрезать до 65535? У меня только одна идея - сравнивать старшие разряды с 0 командой сравнения (PCMPEQW или PCMPGTW). Если использовать PCMPEQW, то получается: если старший разряд равен 0 (результат умножения <= 65535), то в элемент маски пишется $FFFF, если не равен (результат умножения > 65535) - $0000. Ну и далее: Dst := (Low and Mask) or (not Mask) фактически эквивалентно If Mask = $FFFF then Dst := Low else Dst := $FFFF; где Low - младшие разряды. Элементарно, Ватсон? :) Или можно использовать PCMPGTW с 0, тогда логика меняется на противоположную - если результат умножения > 65535, то в маске $FFFF и т.д.
-
-
я так понимаю что 65535 у меня получится если я засвечу картинку в 255 раз? т.е. можно распаковать в mm2 два пиксела, они займут положение 00FF00FF, далее умножить на маску, и максимум что тут получится FFFFFFFF в случае 255 кратной засветки?
еще размышляю, а не покроет ли такая "оптимизация" выигрыш от нескольких "простых" блитингов (пока делаю для конкретной цели - огонь) :)
-
я так понимаю что 65535 у меня получится если я засвечу картинку в 255 раз? т.е. можно распаковать в mm2 два пиксела, они займут положение 00FF00FF, далее умножить на маску, и максимум что тут получится FFFFFFFF в случае 255 кратной засветки?
Ну здесь по сути то же самое, что и с обычным альфа-блендингом (и за основу лучше брать функцию с альфой, а не сложение). Макс. значение пикселя = 255, макс. значение альфы = 255, макс. результат... 65025. Гхм. Ладно, погрешность получается небольшая (65025 shr 8 (/ 256) = 254, всего-то 1/255 яркости) и на глаз незаметная. Для простоты считаю, что макс. значение от умножения двух пикселей = 65535 = High(Word). С точки зрения возможного переполнения именно эта граница имеет значение.
еще размышляю, а не покроет ли такая "оптимизация" выигрыш от нескольких "простых" блитингов
Кстати да, как вариант, если устраивает "грубая" засветка в 2,3 и т.д. раз. Причём можно не делать несколько проходов, а сложить несколько раз в самой ф-ии, тогда однозначно будет быстрее.
-
> Кстати да, как вариант, если устраивает "грубая" засветка > в 2,3 и т.д. раз. Причём можно не делать несколько проходов, > а сложить несколько раз в самой ф-ии, тогда однозначно > будет быстрее.
ну с прозрачностью я сделал (переделал блитинг с общей прозрачностью), можно делать двойное рисование и полупрозрачность поверх (просто в 2-4 раза заметно на глаз, нужна плавность).
с альфой у miek'а довольно хитро, там две маски - прямая и обратная, спрайт умножается на одну, а фон на другую, потом складываются, и потому там все в пределах байта получается (насколько я понял :)). Попробую как нить провернуть, но мне кажется не особо стоит рассчитывать на благоприятный исход (хотя бы в плане скорости) :(
-
MMX-умножение работает только с word'ами, так что в пределах байта не получится. Опять же, как ни инвертируй альфу, а всё равно хотя бы в одном из произведений в максимуме получится 255*255. К пределам байта оно приводится потом командой psrlw mm0, 8. Вообще-то есть такая штука - View FPU window, Ctrl-Alt-F, правой кнопкой на окно, Show -> MMX registers. Делаешь трассировку и смотришь, что и как меняется. Ну и описание команд посмотреть не мешало бы.
По скорости альфа-блендинг, конечно, медленнее аддитивного - больше операций, меньше данных за раз обрабатывается - обычно у меня получалось где-то в 1.5 раза, сейчас на P3 намерил в 2 с лишним.
-
Если ещё надо:
procedure xLine_DrawAddK32_MMX(Src, Dst : Pointer; Count, K : Integer);
asm
push esi
mov esi, eax
imul eax, K, $10001
movd mm5, eax
movq mm4, mm5
psllq mm4, 32
por mm5, mm4
pxor mm7, mm7 pcmpeqb mm6, mm6 @inner_loop:
movd mm0, [esi]
movd mm1, [edx]
punpcklbw mm0, mm7
movq mm2, mm5 pmulhw mm2, mm0 pmullw mm0, mm5 pcmpeqw mm2, mm7 pand mm0, mm2 pxor mm2, mm6 por mm0, mm2 psrlw mm0, 8 packuswb mm0, mm7 paddusb mm0, mm1 movd [edx], mm0
add esi, 4
add edx, 4
dec ecx
jnz @inner_loop
emms
pop esi
end;
По скорости не блестяще, на 15% медленнее альфа-блендинга и всего на 35% быстрее варианта на Паскале. Хотя можно ещё несколько оптимизировать выполнением 2-х умножений за итерацию. Кстати, скорость команд вроде movq mm0, [mem], используемых при обработке 2-х и более пикселей за раз (тот же аддитивный блендинг), сильно зависит от выравнивания (чётная-нечётная x-координата спрайта). Поэтому для нечётных рекомендуется сделать специальную версию спрайта, сдвинутую на 1 вправо, и рисовать её в положении x-1,y.
-
Ещё вполне себе вариант - применение палитровой графики. В небольших спрайтах цветов обычно немного, можно без особых искажений урезать их до 256. Т.е. умножаешь палитру (очень быстро), а потом складываешь MMX-ом. Медленнее, чем сложение 32-битных, но быстрее, чем сложение 32-bpp с умножением.
-
Не, я без ограничений юзаю, обычно даже с альфой везде где можно, без искажений (потому не использую jpeg нигде). Гулять так гулять :)
|