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-21 02:04:00) [41]

Start := fScreen.ScanLine[(Coord.y2work - i)];

емае, я думал что первый пиксель битмапа в fScreen.Height - 1, оказывается он все же в 0, просто обход идет снизу вверх и справа налево....


Вова   (2013-08-21 01:49:00) [42]

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

Start := fScreen.ScanLine[(fScreen.Height - 1 -Coord.y1work- i)];


тут что то не так, но что я понять не могу......

по x примерно совпадает...

причем если Coord.y1work = 0 то проблем нет....


Sha   (2013-08-21 01:42:00) [43]

Попробуй обработать отрезок каждой строки, пересекающей твой квадрат.
Сразу поймешь в чем дело.


Вова   (2013-08-21 00:34:00) [44]

где в последней процедуре ошибка? ( какой то неправильный он мне квадрат вырезает (


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

функционал уже есть. Вчера перевел все что мог на 32 битный битмап (но не на сканлайн)....до сих пор баги исправляю (


ProgRAMmer Dimonych   (2013-08-18 15:20:00) [46]

Может, пора заняться функционалом, а не оптимизацией быстрого?


Вова   (2013-08-17 18:14:00) [47]

единственное, что хорошо в сканлайне, это то что я понимаю как его с фильтром объединить ) Move вообще никак, а ассемблер надо знать как )


Вова   (2013-08-17 17:16:00) [48]

упс......
> И возник вопрос: Как правильно написать, чтобы по x сдвинуть
> копируемый участок? как я сейчас сделал получается какая
> то фигня, слева вроде все нормально, но справа рисуется
> левая часть (которая в копируемый диапазон вроде как не
> попала) картинки источника.


это я исправил еще в том же посте где и спросил ))

function LockConvertBmpToRGBColorMapM(ppixel: pInteger;ppixelDest: pInteger;last:pInteger): Boolean;
begin
 repeat
     ppixelDest^:=ppixel^;
     inc(ppixel);
     inc(ppixelDest);
 until ppixelDest=last;
end;

Procedure TScreenShot.CopyScreenScanLine(var tbmpDest: Tbitmap; Coord: TCoord);
var
 //Source, Destination: Pointer;
 i: Word;
 Destination,Start,Last: pInteger;
begin
for i := 0 to tbmpDest.Height - 1 do
 begin
   //i:=0;
   Start := fScreen.ScanLine[(fScreen.Height - 1 -Coord.y1work- i)];
   inc(Start,Coord.x1work);
   Destination := tbmpDest.ScanLine[tbmpDest.Height - 1 - i];
   Last := Destination;
   inc(Last,tbmpDest.Width);
   LockConvertBmpToRGBColorMapM(Start,Destination,Last);
 end;
end;


ну и в заключении решил дать шанс просто сканлайну, работает немножко медленней чем Move. на картинке размером 500 на 500 пикселей все 3 варианта в пределах одной десятой миллисекунды различаются ))

где же Sha?))


Вова   (2013-08-17 16:57:00) [49]

Вообщем дальнейшие тесты показали, что если копировать небольшие картинки (кусок 500 на 500 разница на 0.1 милисекунды), то заморачиться смысла нет. Тем более, что на ассемблере еще нужно прикручивать выравнивание, а оно тоже чего нибудь отожрет.

И возник вопрос: Как правильно написать, чтобы по x сдвинуть копируемый участок? как я сейчас сделал получается какая то фигня, слева вроде все нормально, но справа рисуется левая часть (которая в копируемый диапазон вроде как не попала) картинки источника.

Procedure TScreenShot.CopyScreenSSE(var tbmpDest: Tbitmap; Coord: TCoord);
var
 Source, Destination: pInteger;
 i: Word;
begin

 //WaitForSingleObject(MyMutex, INFINITE);
 for i := 0 to tbmpDest.Height - 1 do
 begin
   //i:=0;
   Source := fScreen.ScanLine[(fScreen.Height - 1 -Coord.y1work- i)];
   inc(Source,Coord.x1work);
   Destination := tbmpDest.ScanLine[tbmpDest.Height - 1 - i];
   //Move(Source^, Destination^, tbmpDest.Width*4);
   CopySSE(Source, Destination, tbmpDest.Width*4);
 end;
 //ReleaseMutex(MyMutex);

end;


Вова   (2013-08-17 16:05:00) [50]

че то я там с вырезанием  квадрата накосячил )

function LockConvertBmpToRGBColorMapM(ppixel: pInteger;ppixelDest: pInteger;last:pInteger): Boolean;
begin
 repeat
     ppixelDest^:=ppixel^;
     inc(ppixel,1);
     inc(ppixelDest,1);
 until ppixel=last;
 Result := true;
end;

Procedure TScreenShot.CopyScreen(var tbmpDest: Tbitmap; Coord: TCoord);
var
 i: Word;
 Destination,Start,Last: pInteger;
begin

   Start:= fScreen.ScanLine[(fScreen.Height - 1)];
   Last := fScreen.ScanLine[0];
   Destination := tbmpDest.ScanLine[tbmpDest.Height - 1];

   LockConvertBmpToRGBColorMapM(Start,Destination,last);

end;


а так 2.9 (

ассемблер всех обогнал ) только картинка должна быть размером кратно 4


Вова   (2013-08-17 14:42:00) [51]

кратно 8 должно быть?


Вова   (2013-08-17 14:35:00) [52]


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;

Procedure TScreenShot.CopyScreen(var tbmpDest: Tbitmap; Coord: TCoord);
var
 Source, Destination: Pointer;
 i: Word;
begin
 // WaitForSingleObject(MyMutex, INFINITE);
 for i := 0 to tbmpDest.Height - 1 do
 begin
   Source := fScreen.ScanLine[(fScreen.Height - 1 -Coord.y1work- i)-Coord.x1work*4];
   Destination := tbmpDest.ScanLine[tbmpDest.Height - 1 - i];
   //Move(Source^, Destination^, tbmpDest.Width*4);
   CopySSE(Source, Destination, tbmpDest.Width*4)
 end;
 // ReleaseMutex(MyMutex);

end;


в таком варианте в конце картинки не хватает пикселя в конце строки, если кусок длинной 500, но если 504 то хватает... как то я не понял фишку )


Вова   (2013-08-17 14:15:00) [53]

for i := 0 to tbmpDest.Height - 1 do
 begin
   Source := fScreen.ScanLine[fScreen.Height - 1 - i];
   Destination := tbmpDest.ScanLine[tbmpDest.Height - 1 - i];
   CopySSE(Source, Destination, tbmpDest.Width*4)
 end;

а так 2.44


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


Procedure  TScreenShot.CopyScreen(var tbmpDest:TBitmap; Coord:TCoord);
var
 Source,Destination:Pointer;
 i:word;
begin
 for I := 0 to tbmpDest.Height-1 do
 begin
   Source      := fScreen.ScanLine[fScreen.Height-1-i];
   Destination := tbmpDest.ScanLine[tbmpDest.Height-1-i];
   Move(Source^, Destination^, tbmpDest.Width*4);
 end;
end;


если так, то полный скрин 3.5 миллисекунд копируется


Туповатый   (2013-08-17 13:23:00) [55]

Задача не озвучена, но чувствуется, что пытаются гвозди микроскопом забивать. НИМХО


Вова   (2013-08-17 11:03:00) [56]


> Ну тогда ScanLine[fScreen.Height-1].


это спасает, но не сильно. Этой функцией нельзя скопировать кусок памяти источника. Она просто фигачит первую строку скрина, и заполняет ей целевой бмп. Т.е. когда она доходит до конца строки целевого бмп, она переходит на следующую строку его при записи, а вот при чтении скрина нет, она также продолжает идти по той же строке источника.


antonn_tmp   (2013-08-17 10:04:00) [57]

А если окна слоеные и пересекаются, с полупрозрачностями, как сфотографируется окно?


Sapersky   (2013-08-17 01:43:00) [58]

Или подождать, когда у большинства будет Win8 - MS как раз родил специальный API для доступа к десктопу:
http://msdn.microsoft.com/en-us/library/windows/desktop/hh404487(v=vs.85).aspx
Лет 5?


Sapersky   (2013-08-17 01:18:00) [59]

Ну тогда ScanLine[fScreen.Height-1].

Окно - например через GetForegroundWindow, потом GetDC/BitBlt. Непонятно, какой в этом криминал и почему "низя".
Вокруг окна - обычным скриншотом через GetDC(0), в надежде, что площадь будет небольшая и сработает быстро. Точнее, 4-мя скриншотами (сверху, снизу, слева, справа).


Вова   (2013-08-17 01:02:00) [60]

ндааа

Source      := fScreen.ScanLine[0];
 Destination := tbmpDest.ScanLine[0];
 Move(Source^, Destination^, 1500);

такое ощущение, что он копирует только первую строку, а на 1500 уже вылетает по ошибке....точно хз на скольки, но суть в том что что то не то...


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

Наверх

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