![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как ускорить снятие скриншота, Ассемблерная вставка
Вова © (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 уже вылетает по ошибке....точно хз на скольки, но суть в том что что то не то...