Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Спрашивали тут ;)


Страницы:   1 2

homm ©   (2007-10-21 15:05:00) 

Функция AlphaDraw. Принимаемый параметры — 2 32-х битных битмапа, на первый из них рисуется на второй, по альфа маске, которая содержится в резервных битах второго изображения. Изображение копируется на смещение X и Y, которые не должны быть отрицательны.

procedure AlphaDraw(DestBitmap, SourceBitmap: TBitmap; X, Y: Integer);
type
  ARGBQuad = array [0..0] of TRGBQuad;
  PARGBQuad = ^ARGBQuad;
  AByte = array [0..0] of Byte;
  PAByte = ^AByte;
var
  SL1, SL2: PARGBQuad;
  V1, V2: TRGBQuad;
  R: ^TRGBQuad;
  i, j: Integer;
  A_1, A: Integer;
  Delta1, Delta2: DWORD;
  W, H: Integer;
begin
  if (X >= DestBitmap.Width) or (Y >= DestBitmap.Height) then
    exit;
  W := min(SourceBitmap.Width, DestBitmap.Width-X);
  H := min(SourceBitmap.Height, DestBitmap.Height-Y);
  SL1 := DestBitmap.ScanLine[Y];
  SL2 := SourceBitmap.ScanLine[0];
  Delta1 := DWORD(DestBitmap.ScanLine[1]) - DWORD(DestBitmap.ScanLine[0]);
  Delta2 := DWORD(SourceBitmap.ScanLine[1]) - DWORD(SourceBitmap.ScanLine[0]);
  if CPUisMMX then begin
    asm
      pushad

      pxor mm0, mm0
      mov eax, $01010101
      movd mm5, eax
      punpcklbw mm5, mm0
      movq mm6, mm5
      psllw mm5, 8

      mov ecx, H
      push ecx
@@loop1:
        mov esi, [SL2]
        mov edi, [SL1]
        mov eax, [X]
        lea edi, [edi+ eax*4]
        mov ecx, W
@@loop2:

          movd mm1, [esi]
          punpcklbw mm1, mm0
          movd mm2, [edi]
          punpcklbw mm2, mm0

          mov al, [esi + 3]
          mov ah, al
          mov bx, ax
          shl eax, 16
          mov ax, bx

          movd mm4, eax
          punpcklbw mm4, mm0
          paddw mm4, mm6
          movq mm3, mm5
          psubw mm3, mm4

          pmullw mm1, mm3
          pmullw mm2, mm4

          paddw mm1, mm2

          psrlw mm1, 8

          packuswb mm1, mm0
          movd [edi], mm1

          add esi, 4
          add edi, 4
        dec ecx
        jnz @@loop2

        mov eax, [Delta1]
        add [SL1], eax
        mov eax, [Delta2]
        add [SL2], eax
      dec [esp]
      jnz @@loop1

      pop ecx
      emms
      popad
    end;
  end else begin
    for i := 0 to H-1 do begin
      for j := 0 to W-1 do begin
        V1 := SL1[j+X];
        V2 := SL2[j];
        A := V2.rgbReserved+1;
        A_1 := 256-V2.rgbReserved;
        R := @SL1[j+X];
        R.rgbBlue := (V2.rgbBlue*A_1+V1.rgbBlue*A) shr 8;
        R.rgbGreen := (V2.rgbGreen*A_1+V1.rgbGreen*A) shr 8;
        R.rgbRed := (V2.rgbRed*A_1+V1.rgbRed*A) shr 8;
      end;
      SL1 := Pointer(DWORD(SL1) + Delta1);
      SL2 := Pointer(DWORD(SL2) + Delta2);
    end;
  end;
end;


Sapersky   (2007-10-29 16:47:00) [1]

http://www.codenet.ru/cat/Applications/Optimizations/

Но на tommesani описание лучше, ИМХО. Учите буржуйский.
pshufw и т.п.- это enhanced MMX (или integer SSE), соответственно их часто помещают в раздел с SSE.

сделал этот альфаканал, но с ММХ чуть медленней, чем без него получилось

А чем всё-таки PMAXUB(W) не нравится? То, что она на 3/4 будет работать "вхолостую" - не имеет значения, гораздо важнее что не будет cmp/jump.


Pavia   (2007-10-27 00:14:00) [2]

PREFETCHT0. - это не SSE и не MMX

PREFETCHT- выбирать с упреждением. Чтобы не тратиться на загрузку данных в кэш сразу указываем что загрузить.

Насчет, справочника я использую мануэл от Intel, причем не самый последний. Так как последний разбит на два документа, а в не столь старых все в одном.


antonn   (2007-10-26 23:14:00) [3]

PREFETCHT0 - это SSE? встречал пару раз в коде, но не разбирался:)
пользуюсь всякими исходниками и справочником Зубкова С.В. "Ассемблер" в chm (к великому сожалению нет поиска по нему, зато русский и с картинками:)): http://desksoft.ru/index.php?downloads=attachments&id=34(524Кб). pshufw в ней нет, странно...
+ метод научного тыка %)

все таки соврал, ММХ чуть быстрее 1,073832 против 1,10366 "голым кодом" :)


homm   (2007-10-26 22:50:00) [4]

Ах, да интел.ком не предлагать, хочется на Могучем :)


homm   (2007-10-26 22:48:00) [5]

> [30] antonn ©   (26.10.07 22:32)

обрати внимание не команду PREFETCHT0.

Расскажи, заодно, чем пользуешся при написании, потому что я действую почти вслепую… В мануалах, которые ест ьу меня нет такой команды, например как pshufw. В идеале хотелось бы подробный справочник с примерами по всем mmx sse и 3dnow до кучи. Если еше и ч86 будет, вообше замечательно.


antonn   (2007-10-26 22:32:00) [6]

Спасибо!
сделал этот альфаканал, но с ММХ чуть медленней, чем без него получилось :)
   movd      eax, mm0

   rol eax, 8
   mov      bl, byte ptr [esi+3]
   cmp  bl,al
   jb @set_al
   mov al, bl
   @set_al:
   ror eax, 8

   mov      [edi-4], eax


homm   (2007-10-26 21:30:00) [7]

> [28] antonn ©   (26.10.07 20:43)
> а как быстро записать в 4й байт в eax? т.е. для памяти я
> делаю [esi+3] и пишу 4й байт, а как тоже самое сделать для
> регистра?


rol eax, 8
mov al, XXX
ror eax, 8


antonn   (2007-10-26 20:43:00) [8]

а как быстро записать в 4й байт в eax? т.е. для памяти я делаю [esi+3] и пишу 4й байт, а как тоже самое сделать для регистра?


Sapersky   (2007-10-26 12:52:00) [9]

а нет ли такой команды, которая из источника и приемника берет максимальное и кладет в приемник

Точно, есть - PMAXUB. Забыл я про неё, видимо, из-за того, что это enhanced MMX, а не обычный.
http://www.tommesani.com/SSEPrimer.html

Если без MMX, то CMOV. Правда, она избавляет только от jump, cmp или test всё равно нужны.

Что касается "как сделать то и это на обычном asm" - напиши на Паскале и см. CPU window.


antonn   (2007-10-25 23:36:00) [10]

сильно не смяться:)
пишу как в коде [18], просто в конце еще лезу в память, можно как нибудь ускорить?
   mov      [edi-4], eax

   mov       bl, byte ptr [edi-4+3]
   mov       al, byte ptr [esi+3]
   cmp       al,bl
   jb @set_al
   mov      [edi-4+3], al
   @set_al:


antonn   (2007-10-25 23:03:00) [11]

итак, опять я тут %)
в общем, сделал функцию, которая берет для конечного изображения максимальную альфу из исходного и конечного. Сама функция в [9], после обработки третьего байта (как раз перед @skiptransparent:) вставить это:
   mov   al, [edi+3]
   cmp bl,al
   jb @set_al
   mov [edi+3],bl

очень буду рад, если кто нибудь предложит более быстрый вариант (я вот подумал, а нет ли такой команды, которая из источника и приемника берет максимальное и кладет в приемник? тогда этот кусок кода можно до двух строк сократить, а то мне cmp и ждамп как то не нравится:))
но суть не в этом коде, он уже в 7 раз быстрее сканлайна, хочется с ММХ :)
В [18] есть часть кода, сразу после написаного следует
movd      [edi-4], mm0
т.е. в принципе можно запихнуть mm0 в eax, и работать дальше "не с ммх".
Так вот, подскажите, как быть, в EAX значение байта, где альфа берется фоновая. Теперь нужно сравнить альфу источника и фона, и в [eax+3] записать максимальную альфу. Я уже припух, не могу сообразить:)
movd      eax, mm0
..
mov   bl, byte ptr [edi+3]
mov   dl, byte ptr [esi+3]
cmp bl,dl
jb @set_al
//так вот, как в байт eax поместить bl? (или dl, запутался уже)
//mov [edi+3],bl - ессно так нельзя :)
//да и вообще мне кажется, что bl и dl зря взял, испортят они дело:)
@set_al:
..
movd      [edi-4], eax


homm   (2007-10-24 19:43:00) [12]

> [23] Sapersky   (24.10.07 19:09)
> Ну пусть это будет Твоя Гениальная Идея, мне не жалко :)

Я не об авторстве, а о том, что в обоих случаях считаем альфу отдельно, прибавляем к результирующему пикселу.


Sapersky   (2007-10-24 19:09:00) [13]

Ну пусть это будет Твоя Гениальная Идея, мне не жалко :)
Я писал о том, что это можно делать через MMX.

Кстати, ещё следует учитывать: The PCMPGT instructions compare the signeddata elements.


homm   (2007-10-24 18:37:00) [14]

> [21] Sapersky   (24.10.07 18:19)
> Потом примерно так же, как и в MMXTransPut - одну альфу
> and с полученной маской, другую andn, и всё вместе or.

и получется почти как «В крайнем сучае считать альфу до, запоминать, считать пиксель, писать альфу.»


Sapersky   (2007-10-24 18:19:00) [15]

ИМХО можно, хотя не факт, что будет достаточно быстро работать (хоть и MMX, но слишком много операций на пиксель получается, причём значительное кол-во операций ради одной альфы - принцип SIMD нарушается).

The PCMPGT (Packed Compare for Greater Than) instructions compare the signed data elements in the destination operand to the signed data elements in the source operand. If the signed data elements in the destination register are greater than those in the source operand, the corresponding data element in the destination operand is set to all ones, otherwise it is set to all zeros. PCMPGT supports packed byte (PCMPGTB), packed word (PCMPGTW) and packed doubleword (PCMPGTD) data types.

Потом примерно так же, как и в MMXTransPut - одну альфу and с полученной маской, другую andn, и всё вместе or.

Выражаясь псевдокодом:
A1 > A2:
A1 PCMPGT A2 = $FF
(A1 and $FF) or (A2 and (not $FF)) = A1

A1 < A2:
A1 PCMPGT A2 = $00
дальше сам :)


antonn   (2007-10-24 17:54:00) [16]

воблин :(
а в [15] тогда как сделать максимальную в конечном пикселе? а то там сейчас остается от фона.


homm   (2007-10-24 17:41:00) [17]

> [18] antonn ©   (24.10.07 17:31)
> чего то я не пойму, как сделать так, чтобы в первом байте
> была наиболее яркая альфа

С помошью ММХ — никак. В крайнем сучае считать альфу до, запоминать, считать пиксель, писать альфу.


antonn   (2007-10-24 17:31:00) [18]

чего то я не пойму, как сделать так, чтобы в первом байте была наиболее яркая альфа, из той же SpriteUtils.
   push      edi
   push      esi

   pxor      mm7, mm7    

   mov       edx, $10101

   push      $001100FF   // маска первого двойного (11 это альфа, по идее там FF:))
   push      $00FF00FF   // маска второго двойного
   movq      mm5, [esp]  // mm5 - $0011.00FF|00FF.00FF
@outer_loop:
   mov       esi, SrcBits
   mov       edi, DstBits
   mov       ecx, sx

 @inner_loop:
   mov       eax, [esi]
   movd      mm0, [esi]
   test      eax, $FF000000
   jz        @noblend //там просто копирование и цикл дальше
   shr       eax, 24
   add       esi, 4
   imul      eax, edx    // размножить байт прозрачности
   punpcklbw mm0, mm7

   movd      mm6, eax
   movd      mm1, [edi]
   punpcklbw mm6, mm7
   punpcklbw mm1, mm7
   pmullw    mm0, mm6    // получить произведение источника в mm0
   pxor      mm6, mm5    // получить обратную прозрачность в mm6
   pmullw    mm1, mm6    // получить произведение источника в mm0
 
   paddw     mm0, mm1    // сложить

   psrlw     mm0, 8      // переместить в младшую сторону для упаковки

   add       edi, 4

   packuswb  mm0, mm7    // упаковать перед записью на место

//в mm0 конечные 4 байта


Sapersky   (2007-10-22 14:33:00) [19]

вся суть в конвеерной обработке данных, без ветвлений.

Некую имитацию ветвлений можно делать с помощью pcmpeq/pcmpgt и масок, которые они дают; в качестве примера см. вывод с прозрачным цветом (MMXTransPut) из SpriteUtils. Хотя расписывание сколь-нибудь сложного алгоритма с ветвлениями на MMX - это, конечно, кошмар.

Хорошее описание MMX (со схемами - я только по ним и понял, как работает, например, упаковка/распаковка):
http://www.tommesani.com/

А от ассемблера без MMX толку немного. Если хотя бы примерно представлять, как работает оптимизатор и периодически заглядывать в CPU window, можно и на Паскале писать не (ну или не намного) хуже. Система команд ведь та же самая.
По особенностям компилятора есть такой документ:
http://dennishomepage.gugs-cats.dk/CodingForSpeedInDelphi.doc
Не идеальный, но кое-что почерпнуть можно.


antonn   (2007-10-21 22:25:00) [20]


> ЗЫ Идея с GenAlphaTable полностью слизана с Graphics32,
> реализация осмыслена и переработана.

вот из-за этой альфаТайбл я и не стал разбираться с Г32 :)


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо