Alpha blending + AVX2 + Assembler + Linux

Модератор: Модераторы разделов

Ответить
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Alpha blending + AVX2 + Assembler + Linux

Сообщение sabir »

Привет всем!
Собственно название топика говорит само за себя.

Код: Выделить всё

;=======================================================================
; Функция avx_composite_4pixels: ((F * A) + (B * (256 - A))) >> 8
;    rsi = адрес источника
;    rdi = адрес приёмника
;=======================================================================
avx_composite_4pixels:
;-----------------------------------------------------------------------
; загружаем и распаковываем foreground в ymm0 и background в ymm1
;-----------------------------------------------------------------------
    vpmovzxbw ymm0, [rsi]
    vpmovzxbw ymm1, [rdi]
;-----------------------------------------------------------------------
; отщелкиваем альфу в ymm2 из foreground
;-----------------------------------------------------------------------
    vpshufhw ymm2, ymm0, 11111111b
    vpshuflw ymm2, ymm2, 11111111b

    vpsrlw ymm3, ymm2, 7
    vpaddw ymm2, ymm2, ymm3
;-----------------------------------------------------------------------
    vpmullw ymm0, ymm0, ymm2    ; (F * A)
;-----------------------------------------------------------------------
; отщелкиваем (256 - alpha) в ymm4
;-----------------------------------------------------------------------
    vpcmpeqd ymm4, ymm4, ymm4
    vpsrlw ymm4, ymm4, 15
    vpsllw ymm4, ymm4, 8
    vpsubq ymm4, ymm4, ymm2
;-----------------------------------------------------------------------
    vpmullw ymm1, ymm1, ymm4    ; (B * (256 - A)
    vpaddq ymm0, ymm0, ymm1        ; ((F * A) + (B * (256 - A)))
    vpsrlw ymm0, ymm0, 8        ; ((F * A) + (B * (256 - A))) >> 8
;-----------------------------------------------------------------------
    mov rax, 0x00FF000000000000    ; забиваем альфа канал 0xFF
    vmovq xmm2, rax
    vbroadcastsd ymm2, xmm2
    vpor ymm0, ymm0, ymm2

    vpxor ymm1, ymm1, ymm1
    vpackuswb ymm0, ymm0, ymm1

    ret
;-----------------------------------------------------------------------

Все считается правильно, однако результат получается такой (содержимое регистра ymm0):
FF0D5289 FFFFCCAA
00000000 00000000
FF0C4A7C FFE1B69B
00000000 00000000

А мне надо такой (что бы младшая часть регистра ymm0 = xmm0, содержала 4 пикселя, на старшую часть наплевать):
FF0D5289 FFFFCCAA
FF0C4A7C FFE1B69B
00000000 00000000
00000000 00000000

Для того, что бы можно было сделать так:

Код: Выделить всё

vmovdqu [rdi], xmm0        ; сливаем пиксели в приемник

Я в AVX/SSE/MMX не спец, если кто шибко понимает в этом, буду рад доброму совету, может код как то можно улучшить = ускорить.
Решаемая задача: софтварный рендеринг с прозрачностью, нужно очень много и часто делать альфа блэндинг.
Да да, я знаю, CPU не предназначен для работы с графикой, для этих целей уже давно придуман GPU, однако что то мне подсказывает, что GPU юзает ту же технологию, так что это своего рода пробный шар, ну что бы понять как это работает.
Про Mesa OpenGL я тоже знаю, однако она, OpenGL, мне не подходит, т.к. практически намертво привязана в Xorg + гигабайты зависимостей...
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Alpha blending + AVX2 + Assembler + Linux

Сообщение sabir »

Собственно, если это вообще кому то интересно, решение я нашел, а именно:

Код: Выделить всё

vpermpd ymm0, ymm0, 01011000b

Таким образом, если выкинуть все комментарии, то код одновременного альфа блендинга 4-х пикселей будет выглядеть примерно так:

Код: Выделить всё

avx_composite_4pixels:
    vpmovzxbw ymm0, [rsi]        ; загружаем и распаковываем источник
    vpmovzxbw ymm1, [rdi]        ; загружаем и распаковываем приемник
    vpshufhw ymm2, ymm0, 11111111b
    vpshuflw ymm2, ymm2, 11111111b
    vpsrlw ymm3, ymm2, 7
    vpaddw ymm2, ymm2, ymm3
    vmovapd ymm4, [alpha2]
    vpsubq ymm4, ymm4, ymm2
    vpmullw ymm0, ymm0, ymm2    ; (F * A)
    vpmullw ymm1, ymm1, ymm4    ; (B * (256 - A))
    vpaddq ymm0, ymm0, ymm1    ; ((F * A) + (B * (256 - A)))
    vpsrlw ymm0, ymm0, 8        ; ((F * A) + (B * (256 - A))) >> 8
    vmovapd ymm2, [alpha]
    vpor ymm0, ymm0, ymm2
    vpxor ymm1, ymm1, ymm1
    vpackuswb ymm0, ymm0, ymm1
    vpermpd ymm0, ymm0, 01011000b
    vmovdqu [rdi], xmm0
    ret

Где alpha:

align 16
alpha dq 0x00FF000000000000
dq 0x00FF000000000000
dq 0x00FF000000000000
dq 0x00FF000000000000

а alpha2:

align 16
alpha2 dq 0x0100010001000100
dq 0x0100010001000100
dq 0x0100010001000100
dq 0x0100010001000100

По прежнему буду благодарен за совет по оптимизации кода.
Спасибо сказали:
Ответить