![]() |
| ||
|
|
Новости |
Поиск |
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;
как то так делался у меня скриншот, ну примерно в общем не суть, как это объединить?
Sha (2013-08-21 17:50:00) [21]Разумеется, не дает. Но красота - страшная сила!
Замени ленч на каунт в объявлении процедуры - и локальная переменная будет не нужна.
Вова (2013-08-21 17:48:00) [22]все же по идее должно быть так....но на боевых данных вчера так не работало....
Procedure TScreenShot.CopyScreenScanLine(var tbmpDest: Tbitmap; Coord: TCoord);
var
LineLength,SkipLine,i: integer;
Destination, Start, last: pInteger;
begin
WaitForSingleObject(MyMutex, INFINITE);
if (fNumberOfShot = 0) or (tbmpDest.Height < 2) then
exit;
//y*LineLength+x*PixelSize
Start := fScreen.ScanLine[(fScreen.Height - 1) - Coord.y1work];
inc(Start, Coord.x1work);
Destination := tbmpDest.ScanLine[(tbmpDest.Height - 1)];
last := tbmpDest.ScanLine[0];
LineLength := tbmpDest.Width;
SkipLine := fScreen.Width - tbmpDest.Width;
//inc(last, tbmpDest.Width);
LockConvertBmpToRGBColorMapM2(Start, Destination, last,LineLength,SkipLine);
ReleaseMutex(MyMutex);
end;
Вова (2013-08-21 17:35:00) [23]я ничего не пытался даже переворачивать, просто подругому вообще ничего внятного на выходе не получается.
ничо не понял, и это ничего не дает.
function LockConvertBmpToRGBColorMapM2(ppixel: pInteger; ppixelDest: pInteger;
last: pInteger;Lenght,SkipLine:integer): Boolean;
var
count:integer;
begin
count:=Lenght;
repeat
repeat
ppixelDest^ := ppixel^;
inc(ppixel);
inc(ppixelDest);
dec(count);
until count = 0;
count:=Lenght;
inc(ppixel,SkipLine)
until ppixelDest = last;
end;
Sha (2013-08-21 17:27:00) [24]4. опять эти чудеса на виражах с переворотами картинок?
5. остаток строки SkipLine лучше вычислять в вызываемой процедуре.
6. inc(last, tbmpDest.Width); правильнее вычислять дельту между строками, хотя в данном случае это одно и то же.
Sha (2013-08-21 17:16:00) [25]некузяво
1. название? а результат? а варнинг?
2. word? integer!
3. inc(i)? dec(count)!
Вова (2013-08-21 17:00:00) [26]вот зануды.
ассеблер вырезание 500 на 500 делает за 0.468 миллисекунды
мув за 0.515 миллисекунды
Сканлайн в цикле за 0.562 миллисекудны
а сканлайн без сканлайна в цикле за 0.296
function LockConvertBmpToRGBColorMapM2(ppixel: pInteger; ppixelDest: pInteger;
last: pInteger;Lenght,SkipLine:word): Boolean;
var
i:word;
begin
i:=0;
repeat
repeat
ppixelDest^ := ppixel^;
inc(ppixel);
inc(ppixelDest);
inc(i);
until i=Lenght;
i:=0;
inc(ppixel,SkipLine)
until ppixelDest = last;
end;
Procedure TScreenShot.CopyScreenScanLine(var tbmpDest: Tbitmap; Coord: TCoord);
var
LineLength,SkipLine,i: Word;
Destination, Start, last: pInteger;
begin
WaitForSingleObject(MyMutex, INFINITE);
if (fNumberOfShot = 0) or (tbmpDest.Height < 2) then
exit;
//y*LineLength+x*PixelSize
Start := fScreen.ScanLine[Coord.y2work];
inc(Start, Coord.x1work);
Destination := tbmpDest.ScanLine[(tbmpDest.Height - 1)];
last := tbmpDest.ScanLine[0];
LineLength := tbmpDest.Width;
SkipLine := fScreen.Width - tbmpDest.Width;
//inc(last, tbmpDest.Width);
LockConvertBmpToRGBColorMapM2(Start, Destination, last,LineLength,SkipLine);
ReleaseMutex(MyMutex);
end;
проф. Преображенский (2013-08-21 15:27:00) [27]Мне мысли морщат мозг,
От знаний я старею,
Ответьте мне скорее:
А то созрел еще вопрос...
Sha (2013-08-21 15:17:00) [28]двойного?
Sha (2013-08-21 15:17:00) [29]> а отгадка где?
это тот, кто отгадал, должен сказать?
> сканлайн же на начало строки всегда показывает?
она же на границу слова всегда выровнена ?
Вова (2013-08-21 15:09:00) [30]а отгадка где? сканлайн же на начало строки всегда показывает?
Sha (2013-08-21 14:42:00) [31]> что за ScanLine(0); и ScanLine(1); это вообще не понятно.
дык то ж загадка, она не обязана быть понятной
Вова (2013-08-21 14:30:00) [32]1) адрес старта
2) расстояние от начала строки до точки старта + расстояние от конца копируемого отрезка до конца строки;
3) Длина копируемого отрезка (можно BmpDest.Width)
4) адрес конца вырезаемого прямоугольника. (BmpDest.ScanLine(0))
4 переменных, а что за ScanLine(0); и ScanLine(1); это вообще не понятно.
Sha (2013-08-21 14:10:00) [33]А в Вовином случае для перехода к границе квадрата на следующей строке
достаточно увеличить старую границу на d.
Sha (2013-08-21 14:04:00) [34]> Но это нужно лишнюю переменную заводить на каждый сканлайн
> и каждый раз её инициализировать.
Зачем? Достаточно одной... т.е. двух переменных:
a:=ScanLine(0);
d:=ScanLine(1)-a;
А дальше вместо ScanLine(n) использовать a+n*d
Sapersky (2013-08-21 11:57:00) [35]
> Адреса сканлайнов представляют собой арифметическую прогрессию.
Это всё уже обсуждалось:
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1186325580&n=9&from=96
Но это нужно лишнюю переменную заводить на каждый сканлайн и каждый раз её инициализировать.
> Вообще уже пора сайт с картинками сделать, а то нифига невозможно
> понять)
Да, постоянно считать эти перевороты довольно утомительно.
Я в конечном счёте перешёл на не перевёрнутые битмапы (с отрицательной высотой), благо класс-контейнер (TFastDIB) позволяет.
Вова (2013-08-21 11:52:00) [36]
Хотя частые вызовы Scanline в некоторых случаях здорово всё тормозят.
а что тут есть возможность не вызывать часто сканлайн? когда я пытался просто идти как идется, то получалось, что делался проход по всей строке источника.....если наставить условий, что от сих до сих пишем в принимающий битмап, а остальные места просто пропускаем, то будет быстрее, чем если в цикле сканлайн запускать? хм....кстати да, особенно что если выходишь за отрезок который нужно копировать можно не inc(ppixel,1) делать, а сразу длину всего отрезка. над попробовать будет.
Вова (2013-08-21 11:42:00) [37]таки если он в Height-1 то как выходит так, что если я, отнимаю от этого значения координату У верхнего угла целевого прямоугольника и на выходе получаю что прямоугольник вырезается внизу? хотя на деле он вверху ). Таким образом я пошел другим путем, и от 0 взял координату У нижнего угла прямоугольника, и тогда попал в цель. Т.е. когда приращиваешь адрес то идешь от нижнего угла к верхнему.....хотя в данном случае чтобы перейти на следующую строку нужно опять делать сканлайн, так что неочень понятно опять же.
Вообще уже пора сайт с картинками сделать, а то нифига невозможно понять)
Sha (2013-08-21 09:33:00) [38]Адреса сканлайнов представляют собой арифметическую прогрессию.
Просто мысль.
Sapersky (2013-08-21 02:46:00) [39]
> я думал что первый пиксель битмапа в fScreen.Height - 1,
> оказывается он все же в 0
Таки в Height-1, но TBitmap.GetScanline переворачивает координату, задаёшь 0 - будет Height-1.
Если работать со сканлиниями по одной, не пытаясь скопировать/обработать сразу несколько, то по идее о переворотах можно не думать. Хотя частые вызовы Scanline в некоторых случаях здорово всё тормозят.
На уровне WinAPI есть способ создать нормальный, не перевёрнутый битмап - задать ему отрицательную высоту. Но с TBitmap это не работает, разве что наследника писать.
Вова (2013-08-21 02:12:00) [40]скорость поиска теперь доставляет ) пора переходить на микросекунды ) на замеры в микросекундах )