оптимизация кода

Тема в разделе "WASM.BEGINNERS", создана пользователем Diman, 4 янв 2006.

  1. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Помогите с оптимизацией критичного (по времени выполнения) участка кода. Преамбула: функция смешивает цвета по формуле RGB1 * k + RGB2 * (1 - k), где k - коэффициент преобладания одного цвета над другим, значением от 0 до 1. Чтобы избежать операций с плавающей запятой я умножил все части на 10000H. Вот код:

    На входе - 24bitcolor, Src и Dst, Shade - коэффициент преобладания от 0 до 255
    Код (Text):
    1.  
    2. MixColors proc Dst:DWORD, Src:DWORD, Shade:DWORD
    3.        
    4.     mov edx, Shade
    5.    
    6.     cmp dl, 0
    7.     jne m1
    8.     mov eax, Dst
    9.     jmp ExitEntry
    10. m1:
    11.     cmp dl, 0ffh
    12.     jne m2
    13.     mov eax, Src
    14.     jmp ExitEntry
    15.    
    16. m2:
    17.     push ebx
    18.     push esi
    19.     push edi   
    20.  
    21.  
    22.     xor edi, edi
    23.     xor ecx, ecx
    24.     mov ebx, 00010000h
    25.     mov ch, dl      ;ecx = k
    26.     sub ebx, ecx        ;ebx = (1-k)
    27.  
    28.     ;R
    29.     mov eax, Src
    30.     and eax, 0ffh
    31.     mul ecx
    32.     mov esi, eax
    33.    
    34.     mov eax, Dst
    35.     and eax, 0ffh
    36.     mul ebx
    37.     add eax, esi
    38.     shr eax, 16
    39.     and eax, 0ffh
    40.     or edi, eax
    41.    
    42.     ;G
    43.     mov eax, Src
    44.     shr eax, 8
    45.     and eax, 0ffh
    46.     mul ecx
    47.     mov esi, eax
    48.     mov eax, Dst
    49.     shr eax, 8
    50.     and eax, 0ffh
    51.     mul ebx
    52.     add eax, esi
    53.     shr eax, 8
    54.     and eax, 0ff00h
    55.     or edi, eax
    56.    
    57.     ;B
    58.     mov eax, Src
    59.     shr eax, 16
    60.     and eax, 0ffh
    61.     mul ecx
    62.     mov esi, eax
    63.     mov eax, Dst
    64.     shr eax, 16
    65.     and eax, 0ffh
    66.     mul ebx
    67.     add eax, esi
    68.     and eax, 0ff0000h
    69.     or edi, eax
    70.    
    71.     mov eax, edi
    72.    
    73.  
    74.     pop edi
    75.     pop esi
    76.     pop ebx
    77.    
    78. ExitEntry: 
    79.  
    80.     ret
    81. MixColors endp
    82.  


    Учитывая, что размеры обеих картинок большие (1024х768) - код выполняется очень долго.

    Возможно, я сделал алгоритмическую ошибку (может есть более быстрый алгоритм?) или с оптимизацией что-то (но, как тут блин, оптимизировать? Все получается выполнение в одной трубе, так как следующая операция зависит от результата предыдущей). Асы, помогите!!
     
  2. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Немного оклимавшись после праздников улучшил алгоритм. Скорость должна возрасти в 3-4 раза (в основном, за счет отказа от умножения на 10000h). Все удобно перемножается в двух регистрах, процентов 80 кода нормально распаривается в пнях. Завтра покажу результат.
     
  3. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
  4. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
    Откуда эта функция вызывается? Если ты вызываешь ее для каждой точки изображения, то выгоднее перейти на MMX/SSE2 и обрабатывать по 2-4 точки сразу. Вместо mov ch, dl желательно использовать сдвиг влево на 8 разрядов.



    Насчект алгоритмов: почитай ftp://ftp.alvyray.com/Acrobat/4_Comp.pdf по поводу premultiplied alpha. Для твоего случая:


    Код (Text):
    1. RGB1 * k + RGB2 * (1 - k) = RGB1 * k + RGB2 - RGB2 * k = (RGB1 - RGB2) * k - RGB2




    Так можно сократить количество умножений с двух до одного.
     
  5. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Вот обещанная переделка алгоритма:
    Код (Text):
    1.  
    2. MixColors proc Dst:DWORD, Src:DWORD, Shade:DWORD
    3.     ;Algorithm: MixColors = RGB1 * k + RGB2 * (1-k)
    4.     mov edx, Shade
    5.    
    6.     cmp dl, 0
    7.     jne m1
    8.     mov eax, Dst
    9.     jmp ExitEntry
    10. m1:
    11.     cmp dl, 0ffh
    12.     jne m2
    13.     mov eax, Src
    14.     jmp ExitEntry
    15.    
    16. m2:
    17.     push ebx
    18.     push esi
    19.     push edi   
    20.  
    21.     mov esi, Src        ; UV
    22.     mov edi, Dst        ; UV
    23.     mov ebx, esi        ; UV
    24.     mov ecx, edi        ; UV
    25.     and esi, 0FF00FFh   ; UV
    26.     and edi, 0FF00FFh   ; UV
    27.     and ebx, 0FF00h     ; UV
    28.     and ecx, 0FF00h     ; UV
    29.     shr ebx, 8          ; hbz. pairs in UV?
    30.     shr ecx, 8          ; hbz. pairs in UV?
    31.    
    32.     ;Reminder: edx consists Shade value
    33.     mov eax, ebx        ; UV
    34.     mul dl              ; NP, 11c
    35.     mov ebx, eax        ; UV
    36.     neg dl              ; NP, 1c
    37.     mov eax, ecx        ; UV
    38.     mul dl              ; NP, 11c
    39.     add ebx, eax        ;ebx consits G colors mix
    40.     mov ecx, Shade      ; UV
    41.     mov eax, esi        ; UV
    42.     mul ecx             ; NP, 10c
    43.     mov esi, eax        ; UV
    44.     neg cl              ; NP, 1c
    45.     mov eax, edi        ; UV
    46.     mul ecx             ; NP, 10c
    47.     add eax, esi        ; UV
    48.     shr eax, 8          ; hbz
    49.     mov ah, bh          ; UV
    50.    
    51.    
    52.     pop edi
    53.     pop esi
    54.     pop ebx
    55.    
    56. ExitEntry: 
    57.  
    58.     ret
    59. MixColors endp
    60.  




    Скорость возросла, но не на столько, как хотелось бы... Походу, еще не паханное поле для оптимизации.

    Для SDragon - спасибо, комрад, я тоже подумываю в сторону MMX, SSE, вот только я вернулся к асму после 15-ти летнего перерыва, и все что знаю - команды 8080 (гыгг). Придется почитать и про эти новые таинственные фичи...

    На AMD они поддерживаются?
     
  6. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Сколько раз подряд вызывается функция с одним и тем же k?
     
  7. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    cresta wrote:


    Щас скажу: 1024*768 = 786432 раз

    Но это в "упрощенном" режиме, там, где задан всего лишь один коэффициент прозрачности. А если функция вызывается по маске прозрачности - там (особенно, если включен градиент по х и у) может быть для каждого пикселя разное значение.
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




    Значит предвычисление множителя не подходит.
     
  9. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
    Athlon XP поддерживает SSE2, а более ранние AMD'шные процессоры поддерживают MMX. Впрочем функцию, не использующую MMX/SSE, все равно придется писать - для старых процессоров.





    Тогда нужно инлайнить ее. Вызывать функцию 780 тыс. раз в цикле крайне невыгодно. Плюс воспользуйся той формулой, которую я дал выше.
     
  10. Sharp

    Sharp New Member

    Публикаций:
    0
    Регистрация:
    1 авг 2003
    Сообщения:
    143
    Адрес:
    Ukraine
    А если в цикле рассчитывать вперемешку для нескольких пикселов, проц распараллелит?
     
  11. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    За счет открытия для себя инструкции imul (гыгы) удалось еще больше оптимизировать код. Теперь спаривание еще больше и количество спасенных тактов около 8 (без учета спаривания). И это только после 20 страниц чтения интеловского Instruction set reference (vol.2)! Хочу еще больше длинных выходных!
    Код (Text):
    1.  
    2. m2:
    3.     align 4
    4.     push ebx
    5.     push esi
    6.     push edi   
    7.  
    8.     mov esi, Src        ; UV
    9.     mov edi, Dst        ; UV
    10.     mov ebx, esi        ; UV
    11.     mov ecx, edi        ; UV
    12.     and ebx, 0FF00h     ; UV
    13.     and ecx, 0FF00h     ; UV
    14.     shr ebx, 8          ; U
    15.     and esi, 0FF00FFh   ; UV
    16.     and edi, 0FF00FFh   ; UV
    17.     shr ecx, 8          ; U
    18.    
    19.     ;Reminder: edx consists Shade value
    20.     imul ebx, edx
    21.     imul esi, edx
    22.     xor edx, 000000FFh
    23.     mov eax, edi
    24.     imul ecx, edx
    25.     imul eax, edx
    26.     add eax, esi        ; eax consists R and B colors mixes
    27.     add ebx, ecx        ; ebx consits G colors mix
    28.     shr eax, 8
    29.     and ebx, 0000FF00h
    30.     and eax, 00FF00FFh
    31.    
    32.     pop edi
    33.     or eax, ebx
    34.  
    35.     pop esi
    36.     pop ebx
    37.    
    38. ExitEntry: 
    39.  
    40.     ret
    41.  
     
  12. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Так можно избавится от edi, esi, ebx
    Код (Text):
    1. m2:         mov     eax,Src
    2.             and     eax,0x00ff00ff
    3.             imul    eax,Shade
    4.             mov     edx,0xff
    5.             xor     edx,Shade
    6.             mov     ecx,Dst
    7.             and     ecx,0x00ff00ff
    8.             imul    ecx,edx
    9.             add     eax,ecx
    10.             shr     eax,8
    11.             and     eax,0xff00ff
    12.             mov     ecx,Dst
    13.             and     ecx,0xff00
    14.             shr     ecx,8
    15.             imul    ecx,edx
    16.             mov     edx,Src
    17.             and     edx,0xff00
    18.             shr     edx,8
    19.             imul    edx,Shade
    20.             add     ecx,edx
    21.             and     ecx,0xff00
    22.             or      eax,ecx
     
  13. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Что-то мне трудно оценить, что будет быстрее выполняться... Не, на самом деле не знаю. Потестить бы... Код вроде неплохо выглядит, но в глаза бросилось, что большинство кода выполняется в одной трубе, большее число операций с памятью (а что и как будет лежать в кеше на момент обращения для меня - темный лес). Я старался держать значения из памяти в регистрах до последнего, т.е. пока они не будут убиты результатом какой-то операции или не потребуется высвободить регистр.
     
  14. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Радуюсь, как 16 лет назад, когда написал свою первую программу (как щас помню):

    10 PRINT "X{censored}"

    20 GOTO 10

    Уряяя!! :)) Заработала!!



    Привожу теперь код полностью, может кому-то понадобится, или кого из асов покоробит чудовищность моей оптимизации и родится вариант еще шустрее :))


    Код (Text):
    1.  
    2. AlphaBlend proc DstDC:DWORD, DstX:DWORD, DstY:DWORD, DstW:DWORD, DstH:DWORD, SrcDC:DWORD, SrcX:DWORD, SrcY:DWORD, Alpha:DWORD, TransColor:DWORD
    3.     LOCAL TmpDC:HANDLE, TmpBmp:HANDLE, TmpObj:HANDLE
    4.     LOCAL Sr2DC:HANDLE, Sr2Bmp:HANDLE, Sr2Obj:HANDLE
    5.     LOCAL MemData1:DWORD, MemData2:DWORD, MemSize:DWORD
    6.     LOCAL Info:BITMAPINFO
    7.    
    8.     invoke GetTickCount
    9.     push eax
    10.    
    11.     push ebx
    12.     push ecx
    13.     push edx
    14.     push esi
    15.     push edi
    16.    
    17.     mov TmpDC, FUNC(CreateCompatibleDC, SrcDC)
    18.     mov Sr2DC, FUNC(CreateCompatibleDC, SrcDC)
    19.     mov TmpBmp, FUNC(CreateCompatibleBitmap, DstDC, DstW, DstH)
    20.     mov Sr2Bmp, FUNC(CreateCompatibleBitmap, DstDC, DstW, DstH)
    21.     mov TmpObj, FUNC(SelectObject, TmpDC, TmpBmp)
    22.     mov Sr2Obj, FUNC(SelectObject, Sr2DC, Sr2Bmp)
    23.     mov eax, DstW
    24.     imul eax, DstH
    25.     shl eax, 2
    26.     mov MemSize, eax
    27.    
    28.     mov MemData1, FUNC(VirtualAlloc, NULL, MemSize, MEM_COMMIT, PAGE_READWRITE)
    29.     mov MemData2, FUNC(VirtualAlloc, NULL, MemSize, MEM_COMMIT, PAGE_READWRITE)
    30.     mov Info.bmiHeader.biSize, 40
    31.     mov eax, DstW
    32.     mov Info.bmiHeader.biWidth, eax
    33.     mov eax, DstH
    34.     mov Info.bmiHeader.biHeight, eax
    35.     mov Info.bmiHeader.biPlanes, 1
    36.     mov Info.bmiHeader.biBitCount, 32
    37.     mov Info.bmiHeader.biCompression, 0
    38.    
    39.     invoke BitBlt, TmpDC, 0, 0, DstW, DstH, DstDC, DstX, DstY, SRCCOPY
    40.     invoke BitBlt, Sr2DC, 0, 0, DstW, DstH, SrcDC, SrcX, SrcY, SRCCOPY
    41.     invoke GetDIBits, TmpDC, TmpBmp, 0, DstH, MemData1, ADDR Info, 0
    42.     invoke GetDIBits, Sr2DC, Sr2Bmp, 0, DstH, MemData2, ADDR Info, 0
    43.    
    44.     ;int 3
    45.     mov esi, MemData1
    46.     mov edi, MemData2
    47.    
    48.     mov ecx, MemSize
    49.     shr ecx, 2          ; ecx consists counter
    50.     add ecx, 1         
    51. next:
    52.     sub ecx, 1
    53.     jz done             ; if counter == 0 then apply the DIB to device and exit
    54.    
    55.     mov edx, Alpha
    56.     and edx, edx        ; if Alpha == 0 the nothing to do (reserved for a mask usage).
    57.     jz next
    58.    
    59.     mov eax, [edi + ecx*4]
    60.     cmp TransColor, eax     ; if sourcecolor == transparent color then don't touch the destcolor
    61.     je next
    62.     cmp edx, 000000FFh      ; if Alpha == FF then mov destcolor, srccolor, else -> mix the colors
    63.     je WriteToDst
    64.    
    65. MixColors:
    66.  
    67.     push ecx
    68.     push esi
    69.     push edi
    70.    
    71.    
    72.     ;Reminder: eax consists Src value
    73.     mov edi, [esi + ecx*4]
    74.     mov esi, eax ;(Src) ; UV
    75.     mov ebx, eax        ; UV
    76.     mov ecx, edi        ; UV
    77.     and ebx, 0000FF00h  ; UV
    78.     and ecx, 0000FF00h  ; UV
    79.     shr ebx, 8          ; U
    80.     and esi, 00FF00FFh  ; UV
    81.     and edi, 00FF00FFh  ; UV
    82.     shr ecx, 8          ; U
    83.    
    84.     ;Reminder: edx consists Alpha value
    85.     imul ebx, edx
    86.     imul esi, edx
    87.     xor edx, 000000FFh
    88.     mov eax, edi
    89.     imul ecx, edx
    90.     imul eax, edx
    91.     add eax, esi        ; eax consists R and B colors mixes
    92.     add ebx, ecx        ; ebx consits G colors mix
    93.     shr eax, 8
    94.     and ebx, 0000FF00h
    95.     and eax, 00FF00FFh
    96.     or eax, ebx
    97.    
    98.     pop edi
    99.     pop esi
    100.     pop ecx
    101.  
    102. WriteToDst:    
    103.     mov [esi + ecx*4], eax
    104.     jmp next
    105.    
    106.    
    107.  
    108. done:
    109.     invoke SetDIBitsToDevice, DstDC, DstX, DstY, DstW, DstH, 0, 0, 0, DstH, MemData1, ADDR Info, 0
    110.     invoke VirtualFree, MemData1, 0, MEM_RELEASE
    111.     invoke VirtualFree, MemData2, 0, MEM_RELEASE
    112.     invoke DeleteObject, FUNC(SelectObject, TmpDC, TmpObj)
    113.     invoke DeleteObject, FUNC(SelectObject, Sr2DC, Sr2Obj)
    114.     invoke DeleteDC, TmpDC
    115.     invoke DeleteDC, Sr2DC
    116.  
    117.    
    118.     pop edi
    119.     pop esi
    120.     pop edx
    121.     pop ecx
    122.     pop ebx
    123.     pop eax
    124.     sub FUNC(GetTickCount), eax
    125.     ret
    126. AlphaBlend endp
    127.  
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    вход в цикл next можно сделать так:


    Код (Text):
    1.     jmp     _jmp_in
    2. next:
    3.     mov     edx, Alpha
    4.     and     edx, edx   
    5.     ;;;;
    6.     ;;;;
    7.     ;;;;
    8.    
    9. WriteToDest:
    10.     mov     [esi+ecx*4],eax
    11. _jmp_in:
    12.     sub     ecx, 1
    13.     jnz     next                ; if counter != 0 then repeat
    14. done:




    это сэкономит на jmp next, кроме того переход

    and edx,edx

    jz next

    можно будет поменять на переход вперед (что предпочтительней чем назад) :

    and edx,edx

    jz _jmp_in



    Можно сделать процедуру без пролога/эпилога и сэкономить один регистр : ebp, и пустить его за счетчик вместо ecx, и можно будет сэкономить на push ecx/pop ecx и задержки не будет для mov [esi+ecx*4],eax. Только параметры процедуры и локальные надо будет адресовать через esp.
     
  16. zobot1

    zobot1 New Member

    Публикаций:
    0
    Регистрация:
    30 июн 2005
    Сообщения:
    55
    короче может не совсем в тему, но я делал такое на ммх

    пример - 2 картинки - одна фон, другая с альфой (дырки типа). На сколько помню кран 16 битный 565, картинка 1 16 бит, другая 32бит, толь просто буффер только с альфой - не помню чё-то уже (лет 7-8 прошло). А во - спрайт там чё-то типа другого может быть размера нежли фон или чё-то типа того :)


    Код (Text):
    1.  
    2. ; копировка в позицию с альфой с проверкой выхода за экран
    3. ShowPosS_Alpha_:
    4. ;align 16
    5.  
    6.     push ebp
    7.  
    8.     push edx                    ;alpha
    9.  
    10.     mov edi,ebx
    11.     mov esi,eax                 ;graphxSprite
    12.  
    13.  
    14.     mov eax,[esi].nWidth
    15.     mov ebx,[esi].nHeight
    16.     mov [actual_width],eax
    17.     mov [actual_height],ebx
    18.  
    19.     xor eax,eax
    20.     mov [actual_start_spr_x],eax
    21.     mov [actual_start_spr_y],eax
    22.  
    23.  
    24. ; проверка на X
    25.     xor ecx,ecx
    26.     mov ebx,[esi].nPosX
    27.  
    28.     cmp ebx,_width
    29.     jge showpossa_exit      ; if nPosX >= _width
    30.  
    31.     mov [actual_start_x],ebx
    32.     test ebx,1000000000000000b
    33.     jz showpossa_x1         ; >0
    34.  
    35.     mov ecx,ebx
    36.  
    37.     xor ebx,-1
    38.     inc ebx
    39.  
    40.     cmp ebx,[esi].nWidth        ; if nPosX >= nWidth
    41.     jge showpossa_exit
    42.  
    43.  
    44.     mov[actual_start_spr_x],ebx
    45.  
    46.     xor ebx,ebx
    47.     mov [actual_start_x],ebx
    48.  
    49. showpossa_x1:
    50.     add ebx,[esi].nWidth        ; actual_start_x + nWidth
    51.     cmp ebx,_width
    52.     jle showpossa_x2        ; =<_width
    53.  
    54.     push ebx
    55.     sub ebx,_width
    56.     push ebx
    57.     pop eax
    58.     pop ebx
    59.     sub ebx,eax
    60. showpossa_x2:
    61.     sub ebx,[actual_start_x]
    62.     add ebx,ecx
    63.     mov [actual_width],ebx
    64.  
    65. ;
    66.  
    67.  
    68. ; проверка на Y
    69.     xor ecx,ecx
    70.     mov ebx,[esi].nPosY
    71.  
    72.     cmp ebx,_height
    73.     jge showpossa_exit      ; if nPosY >= _height
    74.  
    75.     mov [actual_start_y],ebx
    76.     test ebx,1000000000000000b
    77.     jz showpossa_y1         ; >0
    78.  
    79.     mov ecx,ebx
    80.  
    81.     xor ebx,-1
    82.     inc ebx
    83.  
    84.     cmp ebx,[esi].nHeight       ; if nPosY >= nHeight
    85.     jge showpossa_exit
    86.  
    87.  
    88.     mov[actual_start_spr_y],ebx
    89.  
    90.     xor ebx,ebx
    91.     mov [actual_start_y],ebx
    92.  
    93. showpossa_y1:
    94.     add ebx,[esi].nHeight       ; actual_start_y + nHeight
    95.     cmp ebx,_height
    96.     jle showpossa_y2        ; =<_height
    97.  
    98.     push ebx
    99.     sub ebx,_height
    100.     push ebx
    101.     pop eax
    102.     pop ebx
    103.     sub ebx,eax
    104. showpossa_y2:
    105.     sub ebx,[actual_start_y]
    106.     add ebx,ecx
    107.     mov [actual_height],ebx
    108.  
    109.  
    110.  
    111.  
    112. ; draw
    113.     mov ebp,[actual_width]
    114.     or ebp,ebp
    115.     jz showpossa_exit
    116.     mov ebx,[actual_height]
    117.     mov eax,[actual_start_x]
    118.     mov ecx,[actual_start_y]
    119.  
    120.     shl eax,1
    121.     imul ecx,_width*2
    122.     add edi,ecx
    123.     add edi,eax
    124.  
    125.     mov eax,[actual_start_spr_x]
    126.     shl eax,1
    127.     add eax,[esi].lpBitmap
    128.  
    129.     push ebx
    130.  
    131.     mov ebx,[esi].nWidth
    132.     shl ebx,1
    133.     mov edx,ebx
    134.     imul ebx,[actual_start_spr_y]
    135.     add eax,ebx
    136.     mov esi,eax
    137.  
    138.     pop ebx
    139.  
    140.     pop eax     ; alpha
    141.  
    142. ; eax - lpAlpha
    143. ; esi - In1
    144. ; edi - In2
    145. showpossa_draw2:
    146.     xor ecx,ecx
    147.     push ebp
    148. showpossa_draw1:
    149.     movd mm0,[esi+ecx]  ; 00 00 00 00 xx xx yy yy
    150.     movd mm1,[edi+ecx]  ; 00 00 00 00 aa aa bb bb
    151.  
    152.     push ebx
    153.     xor ebx,ebx
    154.     mov bl,[eax+ecx]
    155.     movd mm2,ebx        ; 00 00 00 00 00 00  aa  aa
    156.     not bl
    157.     movd mm3,ebx        ; 00 00 00 00 00 00 -aa -aa
    158.     pop ebx
    159.  
    160. ; expand 565 to 888
    161.     movq mm4,mm0
    162.     movq mm5,mm0
    163.     movq mm6,mm0
    164.  
    165.     pand mm4,maskR
    166.     pand mm5,maskG
    167.     pand mm6,maskB
    168.  
    169.     psllq mm5,3
    170.     psllq mm6,5
    171.  
    172. ; mm4 - RR
    173. ; mm5 - GG
    174. ; mm6 - BB
    175.  
    176.     por mm5,mm6
    177.     por mm4,mm5
    178.     movq mm0,mm4
    179. ;mm0 - RRGGBB RRGGBB
    180.  
    181.  
    182. ; expand 565 to 888
    183.     movq mm4,mm1
    184.     movq mm5,mm1
    185.     movq mm6,mm1
    186.  
    187.     pand mm4,maskR
    188.     pand mm5,maskG
    189.     pand mm6,maskB
    190.  
    191.     psllq mm5,3
    192.     psllq mm6,5
    193.  
    194. ; mm4 - RR
    195. ; mm5 - GG
    196. ; mm6 - BB
    197.  
    198.     por mm5,mm6
    199.     por mm4,mm5
    200.     movq mm1,mm4
    201.  
    202.  
    203. ;mm1 - RRGGBB RRGGBB
    204. ; --------------------------
    205. ;int 3
    206.     punpcklwd mm2,mm2
    207.     punpcklwd mm2,mm2
    208.  
    209.     punpcklwd mm3,mm3
    210.     punpcklwd mm3,mm3
    211.  
    212.     pxor mm4,mm4
    213.     punpcklbw mm0,mm4
    214.     punpcklbw mm1,mm4
    215.  
    216.     psubw mm0,mm1
    217.     pmullw mm0,mm2
    218.  
    219.     psllw mm1,8
    220.     paddw mm1,round
    221.     paddw mm0,mm1
    222.  
    223.     psrlw mm0,8
    224.     packuswb mm0,mm0
    225. ; --------------------------
    226. ; pack mm0 888 to 565
    227. ; mm0 - 00 00 00 00 00 RR GG BB
    228.     movq mm1,mm0
    229.     movq mm2,mm0
    230.     movq mm3,mm0
    231.  
    232.     pand mm1,mask1
    233.     pand mm2,mask2
    234.     pand mm3,mask3
    235.  
    236.     pxor mm4,mm4
    237.     punpcklbw mm1,mm4
    238.     punpcklbw mm2,mm4
    239.  
    240.     psrld mm2,11
    241.     psrld mm3,5
    242.  
    243.     paddw mm1,mm2
    244.     paddw mm1,mm3
    245.  
    246.     push eax
    247.     movd eax,mm1
    248.     mov [edi+ecx],ax
    249.     pop eax
    250.  
    251.     add ecx,2
    252.     dec ebp
    253.     jnz showpossa_draw1
    254.  
    255.     pop ebp
    256.  
    257.     add edi,_width*2
    258.     add esi,edx
    259.     add eax,edx
    260.  
    261.     dec ebx
    262.     jnz showpossa_draw2
    263.  
    264.     pop ebp
    265.  
    266. showpossa_exit:
    267.  
    268.     emms
    269.  
    270.         ret
    271.  
     
  17. zobot1

    zobot1 New Member

    Публикаций:
    0
    Регистрация:
    30 июн 2005
    Сообщения:
    55
    потерял сёрс чё-то где просто 2 картинки 32bit одного размера с заданным вручную коэф-том накладываются.

    если очень надо дома пороюсь на дисках.
     
  18. Alexey2005

    Alexey2005 New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2006
    Сообщения:
    19
    Адрес:
    Russia
    Diman, увы, оптимизация основного цикла (т.е. собственно "смешения") практически не дает прироста производительности. Как показал прогон под CodeAnalyst, 94% времени выполнения твоей функции приходится на вызовы GetDIBits:
    Код (Text):
    1.     invoke GetDIBits, TmpDC, TmpBmp, 0, DstH, MemData1, ADDR Info, 0
    2.     invoke GetDIBits, Sr2DC, Sr2Bmp, 0, DstH, MemData2, ADDR Info, 0
    3.  
    Этот же вывод подтверждается экспериментально: закомментируй хотя бы один из этих вызовов, и скорость работы функции возрастёт почти вдвое. Но вот даже полное удаление цикла, который ты так тщательно оптимизировал(всего фрагмента next:/done:), не даёт ощутимого прироста скорости. К сожалению, процесс "захвата" битового образа из контекста в WinGDI абсолютно неоптимизирован. Поэтому для ускорения работы в функцию нужно передавать не контексты, а указатели на байты изображения. А вот как обеспечить необходимую скорость "захвата" - даже и не знаю... Разве что DirectX использовать (там-то уж есть достаточно быстрые функции, да и в OpenGL тоже).
     
  19. Diman

    Diman New Member

    Публикаций:
    0
    Регистрация:
    4 янв 2006
    Сообщения:
    8
    Спасибо откликнувшимся - многое из вышеприведенного проверил, взяв лучшее.

    Alexey2005: На самом деле, в WinAPI жуткие тормоза. Переделал алгоритм на MMX - разницы почти никакой (imxo даже на пару миллисекунд (пень2 - 260МГц) медленнее кода на основных регистрах). Но пара миллисекунд это незначительная потеря по сравнению с потерей в ВинАПИ. Закомментил код, оставив только ret: экспериментировал на картинке 400х300, так вот только снапшот десктопа под окном складывался в DIB буфер Data2 около 20мс...

    Тут что еще заморочлся - посмотрел пару туториалов по написанию на ММХ - вроде все хорошо, почерпнул оттуда несколько команд. Вот только в отладчике прокопался два дня (гыгыгы) - все никак не мог понять, а что это у меня обертка (которой проверяю дллку) вылетает на первой же команде с плавающей запятой? Первая мысль была - надо бы состояние mm регистров сохранить, потом - вернуть. Нифига! НУ ХОТЬ БЫ В ОДНОМ ТУТОРИАЛЕ ВСТРЕТИЛАСЬ БЫ ИНСТРУКЦИЯ emms (!!!). Блин!! С такой фигней прокопался 2 дня!! Ну ладно. Вот что получилось:
    Код (Text):
    1.  
    2.     mov eax, edx
    3.     shl eax, 8
    4.     or edx, eax
    5.     shl eax, 8
    6.     or edx, eax                 ; edx = 00.Alpha.Alpha.Alpha
    7.    
    8.     pxor mm0, mm0               ; mm0 = 0
    9.     movd mm3, edx               ; mm3 = Alpha
    10.     xor edx, 00FFFFFFh          ; edx = (256 - Alpha)
    11.     movd mm4, edx               ; mm4 = (256 - Alpha)
    12.  
    13.     punpcklbw mm3, mm0          ; mm3 = 00.00.00.Alpha.00.Alpha.00.Alpha
    14.     punpcklbw mm4, mm0          ; mm4 = 00.00.00.(256-Alpha).00.(256-Alpha).00.(256-Alpha)
    15.    
    16.     mov edx, ebx       
    17.    
    18. @next:
    19.     sub ecx, 1
    20.     jc @done
    21.        
    22.     mov ebx, [edi + ecx * 4]    ; Data2
    23.     mov eax, [esi + ecx * 4]    ; Data1
    24.     and ebx, 00FFFFFFh
    25.     and eax, 00FFFFFFh
    26.     cmp ebx, edx                ; If Data2 == TransparentColor then skip blending
    27.     je @next
    28.  
    29.     ;int 3
    30.     movd mm1, eax               ; Data1
    31.     movd mm2, ebx               ; Data2
    32.    
    33.     punpcklbw mm1, mm0          ; mm1 = 00.00.00.B1.00.G1.00.R1
    34.     punpcklbw mm2, mm0          ; mm2 = 00.00.00.B2.00.G2.00.R2    
    35.    
    36.     pmullw mm1, mm3             ; mm1 = RGB1 * Alpha
    37.     pmullw mm2, mm4             ; mm2 = RGB2 * (256 - Alpha)
    38.    
    39.     paddw mm1, mm2              ; mm1 = RGB1 * Alpha + RGB2 * (256 - Alpha)
    40.    
    41.     psrlw mm1, 8                ; mm1 = (RGB1 * Alpha + RGB2 * (256 - Alpha)) / 256
    42.     packuswb mm1, mm0           ; pack to RRGGBB
    43.    
    44.     movd [esi + ecx * 4], mm1
    45.     jmp @next
    46.    
    47. @done: 
    48.     emms                        ; zero MMX state
    49.     ret
    50.  




    А вот дальше хотелось бы научиться еще и с SSE работать. Но тут выскочили проблемы:

    Интеловский мануал пишет, что нужно сперва инициализировать ССЕ стэйт через регистры CR0 & CR4. Фигасе! А как к ним пробраться из ring4? Да и ML из девятого пакета масма стал ругаться на команду test CR0, 0xFFFFFFFF (так, для эксперимента поставил). Может у кого туториал есть, как писать SSE под виндой?
     
  20. Alexey2005

    Alexey2005 New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2006
    Сообщения:
    19
    Адрес:
    Russia
    Как писать SSE-код под Windows? Просто брать и писать!

    Всю необходимую инициализацию cr0 (если она действительно нужна) ОС выполняет ещё на этапе загрузки. Так что в любой момент можно использовать SSE-команды и они будут работать.

    Правда, тут есть одно НО: SSE-расширение впервые ввели только в Pentium-III. Соответственно, на младших моделях Pentium такой код работать не будет. Определить, поддерживает ли процессор SSE-команды, можно с помощью CPUID:
    Код (Text):
    1. xor eax,eax
    2. inc eax
    3. cpuid
    4. and edx,1000000h
    5. jnz SSEPresent


    Кстати, отладка SSE-кода довольно сложна, т.к. далеко не все отладчики могут показывать содержимое SSE-регистров.