Конференция "Media" » Быстрое копирование битмапов [D5, D6, D7, Win2k, WinXP]
 
  • antonn © (12.01.08 18:04) [0]
    Пересечение веток:
    http://pda.delphimaster.net/?id=1192964708&n=7
    http://pda.delphimaster.net/?id=1192295230&n=7

    и теста  http://pda.delphimaster.net/?id=1200137908&n=3

    Собсно, есть код блитинга битмапов (TBitmap, 32bit), который почему то медленно выполняется на АМД (медленно относительно оппонентов от Интел, я понимаю, что может там мега процы начали делать, но не настолько же круто). Помогите дооптимизировать его :)
  • antonn © (12.01.08 18:05) [1]
    код:
    procedure DrawBitmap_transcolor(BTSource,BTDest:TBitmap; _x,_y:integer; transcolor:TColor);
    var SrcBits: pointer; DstBits: pointer;
       xTo, sx, YTo, ddx, ddy, sy, w, h, dstw, dsth: integer;
       inc1, inc2: integer;
       Sfscanline0,Dfscanline0,fbits:pointer;

       function DIBBits(BMP: TBitmap): Pointer;
       var Section:TDIBSECTION;
       begin
        BMP.HandleType:=bmDIB;
        GetObject(BMP.Handle,sizeof(TDIBSECTION),@Section);
        Result:=Section.dsBm.bmBits;
       end;
    begin
     w:=BTSource.Width;  h:=BTSource.Height;
     dstw:=BTDest.Width;  dsth:=BTDest.Height;
     XTo:=_x+W-1; YTo:=_y+H-1;
     if(_y>=dstH)or(_x>=dstW)or(YTo<0)or(XTo<0) then exit;
     asm
       xor  eax, eax
       mov  ddx, eax
       mov  ddy, eax
     end;
     sx:=W;
     sy:=H;
     if _x<0 then begin
         ddx:=-_x;
         inc(sx,_x);
         _x:=0;
     end;
     if _y<0 then begin
         ddy:=-_y;
         inc(sy,_y);
         _y:=0;
     end;
     if XTo>=dstw then dec(sx,XTo-dstw+1);
     if YTo>=dsth then dec(sy,YTo-dsth+1);

     if (sx<=0)or(sy<=0) then exit;
         
     inc2:=-(((32*w+31) shr 3) and $FFFFFFFC);
     Sfscanline0:=pointer(integer(DIBBits(BTSource))+abs(inc2)*(h-1));
     SrcBits:=pointer(integer(Sfscanline0)+inc2*ddy+ddx*4);

     inc1:=-(((32*dstw+31) shr 3) and $FFFFFFFC);
     Dfscanline0:=pointer(integer(DIBBits(BTDest))+abs(inc1)*(dsth-1));
     DstBits:=pointer(integer(Dfscanline0)+inc1*_y+_x*4);

           asm
             push  ebx
             push  edi
             push  esi

             mov   ebx, TransColor
             and   ebx, $FFFFFF
           @outer_loop:
             mov   edi, DstBits
             mov   ecx, sx
             mov   esi, SrcBits
           @loop:
             mov   eax, [esi]
             mov   edx, [esi]
             and   eax, $FFFFFF
             add   esi, 4
             cmp   eax, ebx
             jz    @next
             mov   [edi], edx
           @next:
             add   edi, 4
             dec   ecx
             jnz   @loop
           @end:
             mov   ecx, inc1
             mov   eax, inc2
             add   DstBits, ecx
             add   SrcBits, eax

             dec   sy
             jnz   @outer_loop
             pop   esi
             pop   edi
             pop   ebx
          end;
    end;



    функция быстрого блитинга, затирает альфаканал.
  • antonn © (12.01.08 18:07) [2]
    ЗЫ понятно дело, что для операций в цикле вычисление адреса первой строки пикселов можно куда нибудь вынести. Но в циклах гонялись битмапы 1600*1200, основная нагрузка идет в асме.
  • Dib@zol © (13.01.08 18:45) [3]
    and   ebx, $FFFFFF
    А нужно ли затирание верхнего байта там, где он не используется? Нафик ету строчку :)

    mov   eax, [esi]
    mov   edx, [esi]
    Чтобы не "дёргать" память дважды, можно заменить последнюю строчку на  mov edx, eax. Правда, прирост производительности при этом мизерный, но етож всётки цикл :)

    А вообще занятный алгоритм. Щас вот думаю, как повязать SrcBits и DstBits на EBP и ESP.
  • Sapersky (13.01.08 19:55) [4]
    Можно попробовать CMOV. Но по моему опыту (на другом алгоритме), толку от неё чуть.
    А если без спец. инструкций - то и asm необязателен, компилятор вполне справляется. Ну будет разница процентов 5, и то не факт, что в пользу "рукописного" варианта.
  • antonn [work) (13.01.08 21:53) [5]
    мне на асме проще )
  • Kenny (13.01.08 22:36) [6]
    Draw alpha with a: 2,8802308673309
    Draw alpha: 1,64891236176665
    Draw alpha MMX: 1,54101373219222
    Draw transparent color: 1,17464649836781
    Draw tr. color opacity MMX: 1,5966358852871
    Draw rotate alpha: 5,10885266144161

    ---
    Pentium M (1.73 Ghz, 533Mhz FSB, 2MB L2 cache)
  • OSokin (15.01.08 18:12) [7]
    А если вот так?

            push  ebx
            push  edi
            push  esi

            mov   ebx, TransColor
            and   ebx, $FFFFFF
          @outer_loop:
            mov   edi, DstBits
            mov   ecx, sx
            mov   esi, SrcBits
          @loop:
            mov   eax, [esi]
            mov   edx, eax
            and   eax, $FFFFFF
            add   esi, 4
            xor   eax, ebx
            jz    @next
            mov   [edi], edx
          @next:
            add   edi, 4
            loop @loop
          @end:
            mov   ecx, inc1
            mov   eax, inc2
            add   DstBits, ecx
            add   SrcBits, eax

            dec   sy
            jnz   @outer_loop
            pop   esi
            pop   edi
            pop   ebx


    Замена на луп дает выйгрыш в 1 байт =). Правда, не проверял, будет работать или нет, но твоя тестилка, модифицированная hiew'ом =), выдает такой результат:
    Draw alpha with a: 7,32291837279389
    Draw alpha: 5,28911366240431
    Draw alpha MMX: 1,9601630027934
    Draw transparent color: 0,899604913674843
    Draw tr. color opacity MMX: 2,22137304124701
    Draw rotate alpha: 9,56283062961568


    До этого было так:
    Draw alpha with a: 7,925456581538
    Draw alpha: 5,84321204678404
    Draw alpha MMX: 2,16867349828345
    Draw transparent color: 0,993406174967481
    Draw tr. color opacity MMX: 2,45866821997455
    Draw rotate alpha: 10,6337005945738

  • antonn © (15.01.08 18:28) [8]

    > OSokin   (15.01.08 18:12) [7]

    верни обратно
    dec   ecx

    и получишь еще медленней :)
  • OSokin (15.01.08 18:32) [9]
    Тьфу, блин. Перепутал результаты =)
  • antonn © (15.01.08 18:34) [10]
    кстати) если вставить loop и убрать dec - ошибок нет, все выполняется) вот только блитится ровно половина (слева) битмапа, поэтому очень быстро:)
  • OSokin (15.01.08 20:04) [11]
    о_О а разве loop @a не равен dec cx / jnz @a ???
    А xor вместо cmp дает что-нибудь?
 
Конференция "Media" » Быстрое копирование битмапов [D5, D6, D7, Win2k, WinXP]
Есть новые Нет новых   [118456   +62][b:0][p:0.005]