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

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

В поисках пикселя - benchmark [D5, Win95/98]


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

Mihey ©   (2004-03-25 17:28:00) 

Ради интереса производил тестирование скорости доступа к пикселям различными средствами: TCanvas.Pixels, Scanline, QPix(TQuickPixels, статья на сайте, а одним из авторов скромно выступил MBo, если не ошибаюсь) и Graphic32( http://www.g32.org, делал тоже наш - Alex Denisov). Для замерения времени был выбран компонент THPCounter- высокоточный таймер, точность до 0,000001 секунды.

Было создано 4 проекта, в которых реализовывалась одна и та же задача: просканировать изображение 800x600с глубиной цвета 24bitи присвоить значение переменной. Измерялась скорость только от начала сканирования до его завершения.

Значение в обычном случае присваивалось переменной типа TColor. Для Scanline была использована функция RGBToColorследующего вида:

function RGBToColor(R,G,B:Byte): TColor;
begin
Result:=B Shl 16 Or
G Shl 8 Or
R;
end;

Проблема вышла с Graphic32. Дело в том, что этот графический пакет определяет свой класс TBitmap32для работы с битмапами, используя при этом свой класс TColor32для хранения цвета - обычный TColor с альфа-каналом. С одной стороны, TColor32 используется в Graphic32 везде и в пределах работы с Graphic32 конвертации не требуется. С другой стороны, хотел соблюсти строгость теста, поэтому в одном из результатов использовалась функция WinColor, возвращающая TColor из TColor32.

Результаты были замерены несколько раз, на глаз выбрано что-то среднее, что ( !) не меняет картину результатов.

Тест выполнялся на компьютере PII 400 MHzс 64 Mb RAM, Win 98.

=====

TCanvas.Pixels
Этот способ показал самый медленный результат - 1.91 секунды.

=====

Scanline
Использовать этот метод довольно неудобно, но тем не менее он дал вполне приемлемый результат - 0.04 секунды.

=====

QPix
Мне он показался очень удобным. создаёшь переменную класса TQuickPixels, присоединяешься к битмапа и всё. Он показал очень хорошую скорость: 0.026 секунды! Пожалуй, если вы хотите работать в переделах класса TBitmap, то используйте этот способ.

=====

Graphic32
Использовать этот графический пакет очень просто. К обычному классу прибавляется постфикс 32 и всё. Теперь подробнее о результатах.

Присваивание переменной типа TColor32 дало результат 0.027 секунды при использовании метода TBitmap32.Pixel sи самый быстрый результат - 0.02 секунды при использовании TBitmap32.Pixel. Поясняю различие: при использовании Pixels учитывается, что координаты пикселя могут выйти из граний изображения, и тогда вернётся некоторое значение OuterColor. Очевидно, что функцию замедляет проверка.

Однако использование TBitmap32.Pixel вместе с функцией WinColor дало результат 0.04 секунды на всё изображение.


cyborg   (2004-03-30 00:03:00) [21]

[39] Mihey ©   (29.03.04 21:05)
У меня игра в 16 бит и всё пучком.


dmk   (2004-03-29 23:50:00) [22]

>Неверно. Чем меньше bpp, тем эффективнее
Я имел в виду выбор между 24 и 32 битами.


Mihey   (2004-03-29 21:05:00) [23]

> Неверно. Чем меньше bpp, тем эффективнее.

Нет уж, не надо нам 16-bit. Это прошлое. Делайте движки, поддерживающие 24- или 32-bit'ные изображения.


miek   (2004-03-29 20:53:00) [24]

>24 бита использовать эффективнее

Неверно. Чем меньше bpp, тем эффективнее.

>Или 1262,3 кадра в секунду =)

Это ж скорость рендеринга, а не вывода. Попробуй вывести на экран, сразу поплохеет, особенно через GDI.

>Получилось, что он на 1-2% эффективнее
чем с командой REP MOVSD.

Можно и нужно быстрее. Посмотри, как у меня (хотя там тоже не предел). www.miek.narod.ru/spriteutils2.zip
Процедура TDIB.PutFast


dmk   (2004-03-29 20:09:00) [25]

Ах да! Совсем забыл. Вот код MoveBytes.
Тестировал на больших и долгих циклах.
Получилось, что он на 1-2% эффективнее
чем с командой REP MOVSD.
По крайней мере на p4.

procedure MoveBytes(SrcAddr, DestAddr, NumBytes: DWord);
asm
 push        edi
 push        esi

 mov         esi, SrcAddr
 mov         edi, DestAddr
 mov         eax, NumBytes
 mov         ecx, eax
 sar         ecx, 2
 push        eax
 jz          @@oB

 @@nP:
 mov         eax, [esi]
 mov         [edi], eax
 add         esi, 4
 add         edi, 4
 dec         ecx
 jnz         @@nP

 @@oB:
 pop         ecx

 and         ecx, 03h
 rep         movsb

 pop         esi
 pop         edi
end;


dmk   (2004-03-29 20:05:00) [26]

2 MegaVolt ©   (29.03.04 15:45) [34]

Заполнение буфера изображением
24 бита использовать эффективнее

На моем P4 2.53GHz получилось
Для 10000 заполнений ушло времени 7.922 секунды
т.е. на одно перемещение буфера 0.00079 десятитысячных секунды.
Это менее 1 миллисекунды.
Или 1262,3 кадра в секунду =)
По моему очень неплохо.

Как то вроде Miek выкладывал скоростной 2D движок.
У него тоже зашкаливало за 700 fps на моей машине =)
Только разрешение было 1024х768.

procedure TMainForm.ToolButton8Click(Sender: TObject);
var
 bmp:          TBitmap;
 sT,eT:        DWord;
 BaseAddr:     Pointer;
 ScLen:        DWord;
 NumPlanes:    DWord;
 bW,bH:        Integer;
 dc:           HDC;
 iSize:        DWord;
 tmp:          Pointer;
 NumCycles:    DWord;

begin
 bmp := TBitmap.Create;
 bmp.LoadFromFile('d:\done\800_600_24.bmp');

 case bmp.PixelFormat of
   pf24bit: NumPlanes := 3;
   pf32bit: NumPlanes := 4;
   else
   begin
     bmp.FreeImage;
     bmp.Free;
     Raise Exception.Create('Unknown pixel depth!');
   end;
 end;

 bW := bmp.Width;
 bH := bmp.Height;

 ScLen := DWord(bW) * NumPlanes;
 BaseAddr := bmp.ScanLine[bH - 1];
 iSize := ScLen * DWord(bH) div NumPlanes;
 GetMem(Tmp, iSize * NumPlanes);

 sT := GetTickCount;

For NumCycles := 0 to 9999 do
  MoveBytes(DWord(BaseAddr), DWord(Tmp), iSize);

 eT := GetTickCount;

 FreeMem(Tmp, iSize);

 dc := GetDC(0);
 BitBlt(dc, 0,0, bW, bH, bmp.Canvas.Handle, 0, 0, SRCCOPY);
 ReleaseDC(0, dc);
 DeleteDC(dc);

 bmp.FreeImage;
 bmp.Free;

 ShowMessage(FloatToStrF((eT - sT) / 1000, ffNumber, 18, 5) + 'секунд затрачено' + #13 +
             FloatToStrF((eT - sT) / 1000 / 10000, ffNumber, 18, 5) + ' секунд на заливку');
end;


miek   (2004-03-29 19:49:00) [27]

>А если нужно просто отобразить ранее подготовленный массив на экране? Возможно какая то дополнительная оптимизация?

Практически никакой, кроме пользования MMX. Тем более, отображаешь экран не ты, а GDI (или DirectX).


MegaVolt   (2004-03-29 15:45:00) [28]

А если нужно просто отобразить ранее подготовленный массив на экране? Возможно какая то дополнительная оптимизация?


goblin   (2004-03-28 00:27:00) [29]

<miek ©   (27.03.04 20:35) [32]
Только для точных измерений лучше, я думаю, не процедуру использовать, а прямо код раскрыть.>
Абсолютно правильно, необходимо также удостоверится, что кэш отдан нам - примитивно, но работает:
Sleep(0) перед вызовом процедур, у которых замеряется время....
Либо многократный вызов - чтобы отбросить влияние загрузки кеша данными (оценка только выполнения кода).
Может я и не прав ...но я пользуюсь этим способом более менее точно.
А для "групповой" забивки пикселей - лучше пользоваться коммандой MOVNTQ ...


miek   (2004-03-27 20:35:00) [30]

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


cyborg   (2004-03-27 18:11:00) [31]

>>[24] dmk ©   (27.03.04 01:26)

Используй для подсчёта:


function GetCPUTick: int64; assembler;
asm
 rdtsc
end;


Точнее измерителя скорости не бывает ;).


Mihey   (2004-03-27 14:29:00) [32]

Последний способ для 32-bit дал такой же результат на моём компе.


miek   (2004-03-27 12:06:00) [33]

>По каким то причинам она работает медленнее чем Mov
>команда rep Stosd составная и крайне неэффективная

Разумеется. Быстрее она будет только на x486

А разворачивать цикл эффективно только до уровня 2 DWORD-а на итерацию, шина все равно больше не возьмет.


dmk   (2004-03-27 02:39:00) [34]

Решил я тоже потестировать скорость.
Загнал все в цикл. Вот так:
For NumCycles := 0 to 511 do
asm
end;

И у меня получилось, что для
32 бит скорость закраски = 1.14 сотых секунды
на 512 заливок 800х600 или 0,0022265625 секунды
на одну заливку.
Для 24 бит скорость закраски = 0.859 тысячных секунды
на 512 заливок 800х600 или 0,001677734375 секунды
на одну заливку.

Это говорит о том, что команда rep Stosd составная и крайне
не эффективная =(. Придется свой движок в некоторых местах переделывать.

PS. Завтра попробую развернуть цикл.
Может еще быстрее будет =)


dmk   (2004-03-27 02:13:00) [35]

А еще лучше так
asm
 push  edi

 mov   eax, c
 bswap eax
 shr   eax, 8

 mov   edx, NumPlanes
 mov   ecx, iSize
 mov   edi, BaseAddr

 @@nP:
 mov   [edi], eax
 add   edi, edx
 dec   ecx
 jnz   @@nP

 pop   edi
end;


dmk   (2004-03-27 02:11:00) [36]

Вся беда в коде REP STOSD.
По каким то причинам она работает медленнее чем Mov.
Замени для 32 бит код на этот. Должно быть быстрее.
asm
  push  edi

  mov   eax, c
  bswap eax
  shr   eax, 8

  mov   ecx, iSize
  mov   edi, BaseAddr

  @@nP:
  mov   [edi], eax
  add   edi, 4
  dec   ecx
  jnz   @@nP

  pop   edi
end;


Mihey   (2004-03-27 01:34:00) [37]

2 dmk:

Последний код выдал 0.006 секунд на такое изображение, и, будь моя программа вирусом, испоганила бы пользователю 150 здоровенных картинок за секунду. Я попробовал тот первый код для 32-битного изображения, но получил меньшую скорость - 0.009 секунд (сравнимо с Graphic32 и Scanline).


dmk   (2004-03-27 01:26:00) [38]

К сожалению у меня на P4-2.53GHz прорисовка происходит настолько быстро, что результат GetTickCount после цикла возвращается тот
же самый. Поэтому у меня время исполнения равно 0.


dmk   (2004-03-27 01:23:00) [39]

Этот код можно ускорить практически до скорости 32 битного.
Достаточно развернуть цикл. Только не переборщи с границами
изображения, а то AV выскочит.


dmk   (2004-03-27 01:16:00) [40]

вместо того ассемблерного кода вставь этот.
Но этот только для 24 бит

 asm
   push  edi

   mov   eax, c
   bswap eax
   shr   eax, 8
   mov   dl, al
   shr   eax, 8

   mov   ecx, iSize
   mov   edi, BaseAddr

   @@nP:
   mov  [edi], dl
   mov  [edi + 1], ax
   add  edi, 3

   dec  ecx
   jnz  @@nP

   pop   edi
 end;


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

Наверх

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