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

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

Как ускорить снятие скриншота, Ассемблерная вставка


Страницы:   1 2 3 4 5 6

Вова ©   (2013-08-14 16:21:00) 

Обнаружил я такой вот код.
Питаю надежду, что он будет работать быстрей моего.

http://www.programmersforum.ru/showthread.php?t=35588

asm
   push esi
   push edx

   mov ecx, BufLength           // размер массива (Integer)
   mov esi, PointerBuf1Scr     // указатель на источник (Pointer)
   mov edx, PointerBuf2Scr    // указатель на приемник (Pointer)

 @@mix:
   movq      xmm0, [esi]     // buf1 -> в регистр
   movq      [edx], xmm0     // buf2 <- из регистра

   add esi, 8
   add edx, 8

   loop @@mix

   pop edx
   pop esi

   emms
 end;


Естественно ничего из написаного мне не понятно. Но исходя из контекста у меня возникло ощущение, что это можно использовать для снятия скриншота. Только вот как это должно выглядеть на делфи я не знаю. В общем то в этом и вопрос.


Procedure   TMyObject.getScreen(var tbmp: Tbitmap; tmpCoord: TCoord);
var
 hDC1: HDC;
 R: TRect;
 Canvas: TCanvas;
begin

 if tmpCoord.x2search = 0 then
   tmpCoord.x2search := screen.Width;

 if tmpCoord.y2search = 0 then
   tmpCoord.y2search := screen.Height;

 hDC1 := GetDC(0);
 Canvas := TCanvas.Create();
 Canvas.Lock;
 Canvas.Handle := hDC1;
 R := Rect(tmpCoord.x1search, tmpCoord.y1search, tmpCoord.x2search,
   tmpCoord.y2search);

 tbmp              := Tbitmap.Create;
 tbmp.Canvas.Lock;
 tbmp.Width        := R.Right  - R.Left;
 tbmp.Height       := R.Bottom - R.Top;
 tbmp.PixelFormat  := pf24bit;
 tbmp.Canvas.CopyRect(Rect(0,0,tbmp.Width,tbmp.Height), Canvas, R);

 ReleaseDC(0, hDC1);
 Canvas.Free;
 Canvas.Unlock;

end;


как то так делался у меня скриншот, ну примерно в общем не суть, как это объединить?


Вова   (2013-08-17 00:54:00) [61]

эм...эт как? окно по хендлу Апи функцией? вот это мне низя. А уж как воокруг еще взять, не скриншотом я и не знаю )


Sapersky   (2013-08-17 00:48:00) [62]

Move(Source^, Destination^, 1000);
Я предлагал брать окно и потом остальное вокруг этого окна с десктопа.


Вова   (2013-08-17 00:45:00) [63]

Source      := fScreen.ScanLine[fScreen.Height-1];
 Destination := tbmpDest.ScanLine[tbmpDest.Height-1];
 Move(Source, Destination, 400);


и так тоже...


Вова   (2013-08-17 00:30:00) [64]


> Я предлагал в [30] брать картинки с окон, ну или хотя бы
> с одного активного окна, таким образом бОльшую часть площади
> экрана можно получить быстрым методом. Хотя если окно рисуется
> не через GDI, а через какой-нибудь Direct2D, тогда наверное
> будет тормозить так же как с десктопом.


не брать скриншот окна не вариант, т.е. я так раньше делал, все круто, но мне так нельзя ))


Вова   (2013-08-17 00:27:00) [65]

Почему CopyScreen ошибку выдает, ошибка записи в память?

Procedure  TScreenShot.CopyScreen(var tbmpDest:TBitmap; Coord:TCoord);
var
 Source,Destination:Pointer;
begin
 //WaitForSingleObject(MyMutex, INFINITE);
 Source      := fScreen.ScanLine[0];
 Destination := tbmpDest.ScanLine[0];
 Move(Source, Destination, 1000);
 //ReleaseMutex(MyMutex);
end;


var
 fScreen: TBitmap;
 tmpCoord: TCoord;
 ScreenObj :TScreenShot;
begin

ScreenObj := TScreenShot.Create;
//ScreenObj.FreeOnTerminate := true;
//ScreenObj.Resume;

fScreen             := TBitmap.Create;
fScreen.Width       := 100;
fScreen.Height      := 100;
fScreen.PixelFormat := pf32bit;
tmpCoord.x1work     := 0;
tmpCoord.y1work     := 0;
tmpCoord.x2work     := 99;
tmpCoord.y2work     := 99;

ScreenObj.getScreen;

Sleep(400);

WaitForSingleObject(ScreenObj.MyMutex, INFINITE);
ScreenObj.ScreenShot.SaveToFile('C:\Scrn.bmp');
ReleaseMutex(ScreenObj.MyMutex);

ScreenObj.CopyScreen(fScreen, tmpCoord);
CODE>


Sapersky   (2013-08-17 00:07:00) [66]

Через DX тоже особо не развернёшься. Брать картинку с экрана (а не из своего окна) без Fullscreen можно только в DX7 и более ранних, при этом единственный способ, который не отключает Aero - копирование в системную память наподобие того же BitBlt. И работает с такой же скоростью или медленнее.

Я предлагал в [30] брать картинки с окон, ну или хотя бы с одного активного окна, таким образом бОльшую часть площади экрана можно получить быстрым методом. Хотя если окно рисуется не через GDI, а через какой-нибудь Direct2D, тогда наверное будет тормозить так же как с десктопом.


Styx   (2013-08-16 21:44:00) [67]


> А банальное GetDC(0) не работает?

Да это не важно. Тормозит-то не здесь. А BitBlt с Aero всегда тормозил и тормозить будет. Не знаю, может, через DirectX быстрей будет, но едва ли.


Алканавт расправил плечи   (2013-08-16 21:14:00) [68]


> чтобы работало, есть конструктивные предложния?
А банальное GetDC(0) не работает? Мне до сих пор хватало его.


Вова   (2013-08-16 19:26:00) [69]

тююю, впомнил что битмап 32 нужен, поменял. разницы никакой.


Вова   (2013-08-16 19:20:00) [70]

procedure TScreenShot.Execute;
var
 T: cardinal;
 i:integer;
begin
     T := GetTickCount;
     for I := 0 to 2000 do
       BitBlt(fhDC1, 0, 0, fScreen.Width, fScreen.Height, fhSrcDC, 0,0, SRCCOPY);

     T := GetTickCount - T;
     fScreen.SaveToFile('C:\test.bmp');
     MessageDlg('Процедура заняла ' + IntToStr(Round(t/2000)) + ' миллисекунд',mtError, [mbOK], 0);

end;


Ощем оттакот, быстрее некуда 46 милисекунд...


Вова   (2013-08-16 18:28:00) [71]


>
> > hSrcDC := CreateDC('DISPLAY', Nil, nil, nil);  hDC1 :=
> CreateCompatibleDC(hSrcDC);
> а это зачем?


чтобы работало, есть конструктивные предложния?


Sapersky   (2013-08-16 05:06:00) [72]

По поводу скриншотов: я заметил, что скорость получения картинки конкретного окна гораздо выше, чем картинки десктопа. Очевидно, из-за того, что в Win7 картинка окна изначально рисуется (если через GDI) в системной памяти, а десктоп со всеми стеклянными рюшечками уже в видео. Можно это использовать.
Ещё, отключение рюшечек (Aero) ускоряет скриншот с десктопа.

А копирование скриншота можно совместить с фильтром, т.е. сделать у фильтра исходную и результирующую картинку.


Вова   (2013-08-16 04:51:00) [73]

нет, 1000 итераций и вычисляется среднее, т.е. 30 за одну.  и это не копирование из одного битмапа в другой, а именно скриншот.


ProgRAMmer Dimonych   (2013-08-16 01:26:00) [74]

> GetTickCount - за 1000 итераций. конечная цель чем быстрее
> тем лучше ) и у меня пока есть ощущение, что еще есть куда
> быстрее. ну не фильтр быстрее 2 миллисекунд, а все остальное
> ) тем более у меня есть еще 1 фильтр он очень тормозной
> ) есть куда стремиться )

GetTickCount() точнее 15 мс не расскажет. И, пардон, если 1000 копирований выполняется за 30 мс, то кто-то растрачивает своё время на экономию на спичках.

1. Скопировать кусок памяти быстрее, чем за O(N) не удастся и оптимизации с ассемблером и инструкциями не помогут сделать O(log N).
2. С низкоуровневыми оптимизациями надо очень осторожно, ибо здесь и сейчас работает шустро, а завтра что-то поменялось (процессор, версия ОС) — и вдруг оказывается, что так только хуже (если не ошибаюсь, те же loop/loopcc на старых процессорах были быстрее, чем циклы с jcc, сейчас наоборот). Плюс сопровождаемость падает: наоптимизировав, можно выжать лишние 15 мс, а через полгода не понять ни строчки. Да ещё и для нового формата данных оптимизация окажется неподходящей.
3. Написанием своих замен для стандартных функций (тех же GDI) лучше не злоупотреблять: Microsoft не гарантирует, что в одной из следующих версий не изменятся внутренние структуры данных. Хотя битмап-то вряд ли, конечно.


Вова   (2013-08-16 01:07:00) [75]


> А конечная цель тогда сколько? И чем сделаны замеры с 2
> мс?


GetTickCount - за 1000 итераций. конечная цель чем быстрее тем лучше ) и у меня пока есть ощущение, что еще есть куда быстрее. ну не фильтр быстрее 2 миллисекунд, а все остальное ) тем более у меня есть еще 1 фильтр он очень тормозной ) есть куда стремиться )


ProgRAMmer Dimonych   (2013-08-16 01:03:00) [76]

> ну самое забавное как раз в том, что благодаря Sha теперь
> самое узкое место у меня скриншот ) потому что фильтр делается
> за 2 милисекунды, что как то теряется на фоне 30 миллисекунд
> за скриншот ) ну и все что осталось на небольших участках
> картинки тож в пределах 30 миллисекунд пролетает )

А конечная цель тогда сколько? И чем сделаны замеры с 2 мс?


Вова   (2013-08-16 00:59:00) [77]


> В данном случае ради результата как раз не стоит заморачиваться
> - наверняка копирование картинки (тем более фрагмента картинки)
> не будет узким местом, всё остальное будет тормозить сильнее.
>  BitBlt с экрана, обработка, сжатие или что там у тебя -
>  на этом фоне ускорение копирования в 2 раза не будет заметно.
>


ну самое забавное как раз в том, что благодаря Sha теперь самое узкое место у меня скриншот ) потому что фильтр делается за 2 милисекунды, что как то теряется на фоне 30 миллисекунд за скриншот ) ну и все что осталось на небольших участках картинки тож в пределах 30 миллисекунд пролетает )


Sapersky   (2013-08-15 23:51:00) [78]


> antonn_tmp   (15.08.13 20:12) [22]

Про movups - да, слышал, что медленная, поэтому даже не пробовал. Я уже как-то привык, что любому SIMD нужно выравнивание.


> Rouse_ ©   (15.08.13 21:48) [23]

Я не утверждал, что это универсальная замена Move на все случаи жизни. Если бы подходило для всех случаев, оно бы уже давно было в RTL.

Type
 PByteArr = ^TByteArr;
 TByteArr = array [0..MAXINT-1] of Byte;
 DByteArr = array of Byte;

function Arr_Aligned(Var Arr : DByteArr; ByteSize : Integer; AShift : Integer = 3): Pointer;
Var i, Offs : NativeInt;
   AVal : Integer;
begin
AVal := (1 shl AShift);
SetLength(Arr, ByteSize + AVal);
i := NativeInt(Arr);
While ( ((i shr AShift) shl AShift) <> i ) do
 Inc(i, 4);
Result := Pointer(i);
end;

procedure TForm1.Button2Click(Sender: TObject);
Const
 Cycles = 100000;
 Size = 64 * 1024;
Var n : Integer;
   a : DByteArr;
   pa : PByteArr;
   S: Cardinal;
begin
pa := Arr_Aligned(a, Size*2, 4);
For n:=0 to Size-1 do pa[n] := n;
S := GetTickCount;
For n:=0 to Cycles-1 do
 CopySSE(pa, @pa[Size], Size);
//  Move(pa[0], pa[Size], Size);
Caption := InttoStr(GetTickCount - S);
end;

(ну или можно включить в FastMM опцию "выравнивать на 16")

А про код из [0] никто не сомневается, что он нерабочий, не мучай трупик.


Rouse_   (2013-08-15 21:48:00) [79]


> antonn_tmp   (15.08.13 20:12) [22]
> Требование к выравниванию у movaps, movups переварит и невыровненные

Скорее AV c кодом С0000005 будет, впрочем, предлагаю потестировать всем желающим данный код под ХЕ4:

program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses
 windows,
 System.SysUtils;

Procedure   Copy1(BufLength:Integer; PointerBuf1Scr:Pointer; PointerBuf2Scr    : Pointer);

asm
  push esi
  push edx

  mov ecx, BufLength           // размер массива (Integer)
  mov esi, PointerBuf1Scr     // указатель на источник (Pointer)
  mov edx, PointerBuf2Scr    // указатель на приемник (Pointer)

@@mix:
  movq      xmm0, [esi]     // buf1 -> в регистр
  movq      [edx], xmm0     // buf2 <- из регистра

  add esi, 8
  add edx, 8

  loop @@mix

  pop edx
  pop esi

  emms
end;

procedure CopySSE(Src, Dst : Pointer; Cnt : Integer);
asm
  shr ecx, 5
@@mix:
  movapd xmm0, [eax]
  movapd xmm1, [eax+16]
  movapd [edx], xmm0
  movapd [edx+16], xmm1
  add eax, 32
  add edx, 32
  dec ecx
  jnz @@mix
end;

var
 A: array [0..63] of Byte;
 B: array [0..63] of Byte;
 S: Cardinal;
 I: Integer;
begin
 try
   S := GetTickCount;
   for I := 0 to 1000 do
     CopyMemory(@a[0], @b[0], 64);
   Writeln(GetTickCount - S);
   S := GetTickCount;
   for I := 0 to 1000 do
     CopySSE(@a[0], @b[0], 64);
   Writeln(GetTickCount - S);
   S := GetTickCount;
   for I := 0 to 1000 do
     Copy1(64, @a[0], @b[0]);
   Writeln(GetTickCount - S);
 except
   on E: Exception do
     Writeln(E.ClassName, ': ', E.Message);
 end;
 readln;
end.


CopySSE выдаст:
Project Project2.exe raised exception class $C0000005 with message 'access violation at 0x00418d57: read of address 0xffffffff'.

а Copy1 (переименованная процедура от "Вова   (14.08.13 16:26) [1]") выдаст вообще печальную картинку (обратите внимание на изменения итератора I на каждой итерации цикла)


antonn_tmp   (2013-08-15 20:12:00) [80]

Требование к выравниванию у movaps, movups переварит и невыровненные, но скорость будет не выше чем через РОН :)


Страницы:   1 2 3 4 5 6

Наверх

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