Как увеличить скорость отрисовки на canvas?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Как увеличить скорость отрисовки на canvas?

Сообщение debi12345 » 02.03.2014 23:20:08

Для RPI с его 700 MHz + GPU, против ~4MHz у Z80, не актуальна

ТС пишет что очень актуальна %). И спасти может только GPU-акселерация. По сути проц нужен машинке для загрузки "оси" :)

а вызов виртуаального метода это всеголишь взятие адреса метода по известному смещению

Ничего не попутали ? АФАЙК, какой конкретно метод вызвать можно узнать только перед самым вызовом (т.п. позднее связывание после анализа VMT). То,что Вы имеет ввиду - предопределенные на этапе компиляции или прописываемые на стартапе указатели на функции см MSEgui.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 02.03.2014 23:33:29

>>ТС пишет что очень актуальна %).
Нет, MiniQ пишет про очень медленный доступ процем в видеопамять (или что там у rpi)
>>какой конкретно метод вызвать можно узнать только перед самым вызовом
Какой конкретно метод известно на этапе компиляции, не известно что за инстанс будет подсунут в рантайме = смещение в вмт известно, не известен адрес вмт. Вот и получается для class'а первый указатель - инстанс, второй указатель его вмт, далее по известному смещению.
В случае object`а созданного на стеке остается всего один указатель сразу на вмт

Добавлено спустя 23 минуты 52 секунды:
Mirage
>>Зато интересная.
Имхо основная сложность во всей этой затее будет не "гигабайтики" и не тексты-ttfы, а реализовать простой и понятный интерфейс между контролом и гээлем, в смысле хранения-передачи разной "нагрузочной" гээле зависимой информации - контексты, текстуры, вершинные буфера и т.п. Это хозяйство логично хранить вместе с контролом (это ведь его представление в GL контексте), но контролу оно ненужно, нужно только на уровне отрисовки.
Причем так чтоб потом можно было легко сделать например dx (или gdi+ или x11) отрисовку - реализуем саму отрисовку и меняем структуру хранимой с контролом "нагрузочной" информации просто унаследовавшись от соответствующих классов
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение debi12345 » 03.03.2014 00:04:14

Проверил - виртуал проигрывает 8..10% даже на поиске среди 3 виртуальных методов. А если их будут десятки и сотни ?
Над тесткэйсом просьба не смеяться - это в спешке :) "cnt" большой чтобы уменьшить влияние кэширования и т.п.
Код: Выделить всё
program virtcheck;

{$mode objfpc}{$h+}{$apptype console}{$interfaces corba}

uses
   windows, SysUtils, Math;

const
  cnt = 1000000000;

type
  nonvirt = class
    procedure f1(i: integer);
  end;

  virtparent = interface
    procedure f1(i: integer);
  end;

  virt1 = class (virtparent)
    procedure f1(i: integer); virtual;
  end;

  virt2 = class (virtparent)
    procedure f1(i: integer); virtual;
  end;

  virt3 = class (virt2)
    procedure f1(i: integer); override;
  end;

  function LARGE_INT2INT64(A: LARGE_INTEGER):int64; inline;
  begin
    result:= int64(dword(A.LowPart) + ((qword(A.HighPart)) shl 32));
  end;

procedure nonvirt.f1(i:integer);
begin
  i:= i+1;
end;

procedure virt1.f1(i:integer);
begin
  i:= i+2;
end;

procedure virt2.f1(i:integer);
begin
  i:= i+3;
end;

procedure virt3.f1(i:integer);
begin
  i:= i+4;
end;


var
  i: integer;
  T1,T2, FREQ: LARGE_INTEGER;
//  v_virtparent: virtparent;
  v_nonvirt: nonvirt;
  v_virt1: virt1;
  v_virt2: virt2;
  v_virt3: virt3;

begin

  QueryPerformanceFrequency(@FREQ);

  v_nonvirt:= nonvirt.create;
  v_virt1:= virt1.create;
  v_virt2:= virt2.create;
  v_virt3:= virt3.create;

  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
   v_nonvirt.f1(i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('non virt for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
   v_virt1.f1(i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('virt1 for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    v_virt2.f1(i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('virt2 for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    v_virt3.f1(i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('virt3 for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

end.


Добавлено спустя 3 минуты 47 секунд:
Также вызов из класса проигрывает 1..2% вызову обычной функции.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 00:17:22

Это тонкий тролинг? я про виртуальный метод, вы про интерфейсы...
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение debi12345 » 03.03.2014 00:26:08

А вот с маршаллингом и VMT-поиском на каждом вызове:
Код: Выделить всё
procedure f(vp:virtparent; i: integer);
begin
  vp.f1(i);
end;
[...]
  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    f(v_virt1,i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('f for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

имеем 10-кратное замедление, то есть о-о-оочень серьезные тормоза.

я про виртуальный метод, вы про интерфейсы.

Интерфейс принуждает ииспользовать виртуальный метод. Первое что пришло на ум.

Добавлено спустя 26 минут 23 секунды:
Вывод - в молотильном коде категорически нельзя использовать поздне-связной полиморфизм, а данном случае - передачу предкового класса или интерфейса как параметра функции для вызова его виртуальных методов внутри этой функции.

Добавлено спустя 10 минут 12 секунд:
Маршаллинг через стек, без полиморфизма :
Код: Выделить всё
procedure fa(const c:virt1; i: integer);
begin
  c.f1(i);
end;
[..]
  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    fa(v_virt1,i);
  end;
  QueryPerformanceCounter(@T2);
  writeln('fa for cnt=',i,': ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

замедление в 2 раза. Тоже ничего хорошего.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 01:13:09

Код: Выделить всё
program Project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this },sysutils;
type
  TParamType=Integer;
  PTMyObject=^TMyObject;
  TMyObject=object
                  function test(param:TParamType):TParamType;
  end;
  PTMyObjectV=^TMyObjectV;
  TMyObjectV=object
                  function test(param:TParamType):TParamType;virtual;
                  constructor init;
  end;
  TMyClass=class
                  function test(param:TParamType):TParamType;
  end;
  TMyClassV=class
                  function test(param:TParamType):TParamType;virtual;
  end;
  TTestFunc=function(param:TParamType):TParamType of object;
var
  MyObject:TMyObject;
  PMyObjectV:PTMyObjectV;
  MyClass:TMyClass;
  MyClassV:TMyClassV;
  myFunc:TTestFunc;
function TMyObject.test(param:TParamType):TParamType;
begin
     result:=param+1;
end;
function TMyObjectV.test(param:TParamType):TParamType;
begin
     result:=param+1;
end;
constructor TMyObjectV.init;
begin
end;
function TMyClass.test(param:TParamType):TParamType;
begin
     result:=param+1;
end;
function TMyClassV.test(param:TParamType):TParamType;
begin
     result:=param+1;
end;
const
     cyclecount=maxint;
var i,r:TParamType;
    time:TTime;
begin
  new(PMyObjectV,init);
  MyClass:=TMyClass.create;
  MyClassV:=TMyClassV.create;
  myFunc:=@MyClass.test;

  time:=now;
  for i:=0 to cyclecount do
                           r:=myFunc(i);
  writeln('myFunc(i)=',round((now-time)*10e7));

  time:=now;
  for i:=0 to cyclecount do
                           r:=MyClass.test(i);
  writeln('MyClass.test(i)=',round((now-time)*10e7));

  time:=now;
  for i:=0 to cyclecount do
                           r:=MyClassV.test(i);
  writeln('MyClassV.test(i)=',round((now-time)*10e7));

  time:=now;
  for i:=0 to cyclecount do
                           r:=MyObject.test(i);
  writeln('MyObject.test(i)=',round((now-time)*10e7));
  time:=now;
  for i:=0 to cyclecount do
                           r:=PMyObjectV^.test(i);
  writeln('PMyObjectV^.test(i)=',round((now-time)*10e7));

  readln;
end.

myFunc(i)=7549 - вызов по адресу в переменной
MyClass.test(i)=7235 - невиртуальный метод класса
MyClassV.test(i)=7985 - виртуальный метод класса
MyObject.test(i)=7307 -невиртуальный метод объекта
PMyObjectV^.test(i)=8084 -виртуальный метод объекта

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

>>имеем 10-кратное замедление, то есть о-о-оочень серьезные тормоза.
:shock:
имеем замедление в 5% на коде которй выполняет только вызовы в цикле (сравниваю процедура vs виртуальный метод класса). учтем что реальный код состоит не только из вызовов, учтем что интерфейс довольно неторопливая вещь и не перерисовывается в цикле... В нормальном реальном приложении (с вызовом виртуальных методов не на каждый перерисованный пиксел, а там где действительно надо) вы не заметите никакой разницы
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение debi12345 » 03.03.2014 01:47:15

Помню мы с Вами тестировали TOBject и выяснили что он очень быстр по сути не проигрывая прямому доступу через указатель (после чего я взял на заметку темплэйтную DeCAL).
Но в данном обсуждении народ намекает на полиморфизм (чтобы заменить переключаемые адреса простых функций на ООП-подход) такого вида:
Код: Выделить всё
program test_gui;
{$mode objfpc}{$h+}{$apptype console}{$interfaces corba}

uses
   windows, SysUtils, Math;

  function LARGE_INT2INT64(A: LARGE_INTEGER):int64; inline;
  begin
    result:= int64(dword(A.LowPart) + ((qword(A.HighPart)) shl 32));
  end;

const
  cnt = 1000000000;

type

  guiif = interface
    procedure draw_point(x,y: integer);
  end;

  gui_qt = class(guiif)
    procedure draw_point(x,y: integer); virtual;
  end;

  gui_gl = class(guiif)
    procedure draw_point(x,y: integer); virtual;
  end;

  procedure draw_point(x,y: integer);
  begin
    x:= x+y;
  end;
 
  procedure gui_qt.draw_point(x,y: integer);
  begin
    y:= x+y;
  end;

  procedure gui_gl.draw_point(x,y: integer);
  begin
    x:= x-y;
  end;

var
  i: integer;
  activegui: guiif;
  v_gui_qt: gui_qt;
  v_gui_gl: gui_gl;
  T1,T2, FREQ: LARGE_INTEGER;

begin

  QueryPerformanceFrequency(@FREQ);
  v_gui_qt:= gui_qt.create;
  v_gui_gl:= gui_gl.create;

  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    draw_point(i-100,i+100);
  end;
  QueryPerformanceCounter(@T2);
  writeln('simple func: ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

  activegui:= v_gui_qt;
  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    activegui.draw_point(i-100,i+100);
  end;
  QueryPerformanceCounter(@T2);
  writeln('qt polimoph: ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

  activegui:= v_gui_gl;
  QueryPerformanceCounter(@T1);
  for i:=0 to cnt do begin
    activegui.draw_point(i-100,i+100);
  end;
  QueryPerformanceCounter(@T2);
  writeln('gl polimoph: ',1000000*(extended(LARGE_INT2INT64(T2) - LARGE_INT2INT64(T1)))/extended(LARGE_INT2INT64(FREQ)),'microseconds');

end.

Здесь даже без маршаллинга имеем проигрыш в 6 раз относительно вызова простой функции. Думаете, такие тормоза для молотильного кода можно оправдать применением "передового подхода" ?
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 08:27:49

Уберите вы этот guiif = interface, используйте обычные классы, зачем он здесь? и "разы" уйдут, останутся проценты.
>>Помню мы с Вами тестировали TOBject и выяснили что он очень быстр по сути не проигрывая прямому доступу через указатель (после чего я взял на заметку темплэйтную DeCAL).
Не TOBject, а просто object)) тут от него проку небудет
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение MiniQ » 03.03.2014 10:03:51

Коллеги, давайте не будем скатываться в крайности, и подменять основную тему топика - использование аппаратного ускорения при отрисовке интерфейса.
Способы вызова методов - ловля блох.
MiniQ
новенький
 
Сообщения: 81
Зарегистрирован: 28.01.2013 16:31:55

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 10:13:36

вот более осмысленный тест - полиморфизм, 2 разных виртуальных реализации vs вызов через указатель на функцию
Код: Выделить всё
program Project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this },sysutils;
type
  TParamType=Integer;
  TMyBaseClass=class
                  function test(TestImpl:Boolean;param:TParamType):TParamType;virtual;abstract;
  end;
  TMyClass1=class (TMyBaseClass)
                  function test(TestImpl:Boolean;param:TParamType):TParamType;override;
  end;
  TMyClass2=class (TMyBaseClass)
                  function test(TestImpl:Boolean;param:TParamType):TParamType;override;
  end;
  TTestFunc=function(TestImpl:Boolean;param:TParamType):TParamType;
function TMyClass1.test(TestImpl:Boolean;param:TParamType):TParamType;
begin
     If TestImpl then
                     begin
                          write('TMyClass1.test');
                     end
                 else
                     result:=param + 1;
end;
function TMyClass2.test(TestImpl:Boolean;param:TParamType):TParamType;
begin
     If TestImpl then
                     begin
                          write('TMyClass2.test');
                     end
                 else
                     result:=param + 1;
end;
function test(TestImpl:Boolean;param:TParamType):TParamType;
begin
     If TestImpl then
                     begin
                          write('function test');
                     end
                 else
                     result:=param + 1;
end;

const
     cyclecount=maxint;
var i,r:TParamType;
    time:TTime;
    myFunc:TTestFunc;
    MyClass:TMyBaseClass;
    MyImpl1:TMyClass1;
    MyImpl2:TMyClass2;
begin
  MyImpl1:=TMyClass1.create;
  MyImpl2:=TMyClass2.create;
  myFunc:=@test;

  time:=now;
  for i:=0 to cyclecount do
                           r:=myFunc(false,i);
  myFunc(true,0);
  writeln(' x ',cyclecount,' = ',round((now-time)*10e7),'msec');

  MyClass:=MyImpl1;
  time:=now;
  for i:=0 to cyclecount do
                           r:=MyClass.test(false,i);
  MyClass.test(true,0);
  writeln(' x ',cyclecount,' = ',round((now-time)*10e7),'msec');

  MyClass:=MyImpl2;
  time:=now;
  for i:=0 to cyclecount do
                           r:=MyClass.test(false,i);
  MyClass.test(true,0);
  writeln(' x ',cyclecount,' = ',round((now-time)*10e7),'msec');

  readln;
end.

вывод с включенной максимальной оптимизацией
function test x 2147483647 = 6941msec
TMyClass1.test x 2147483647 = 6926msec
TMyClass2.test x 2147483647 = 6946msec

Хз, толи компилер понял что от "виртуальности" можно уйти, толи настолько соптимизировал, НО РАЗНИЦЫ НИКАКОЙ НЕТ

вывод без оптимизации
function test x 2147483647 = 9285msec
TMyClass1.test x 2147483647 = 9667msec
TMyClass2.test x 2147483647 = 9669msec

ГДЕ РАЗНИЦА В РАЗЫ? Вижу только ~4%.

MiniQ
>>Способы вызова методов - ловля блох.
Ага, ловля блох которых нет

Основная тема топика с отрисовкой интерфейса какраз не пересекается))
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение xterro » 03.03.2014 11:49:53

О, только отвернулся, уже столько всего понаписали ))))

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

А что тогда на экране будет? Ведь всё изображение "смажется". Т.е сдвинули скрол, точки должны перерисоваться в новых позициях, т.е стираем экран и рисум точки по новым координатам. Если контрол не перерисовать, то я даже не заню что получится.

Лучше мне вот что расскажите, как такие вещи вообще устроены. Попробую описать как я это понимаю.
Изначально у нас есть одна одна область, скажем размеров 1000х1000 IU (внутренних единиц). В качестве IU возмём скажем Mils, 1Mils это 0,0254 мм, и установим соотношение, что 1 пиксель это у нас 20 mils. Далее, на этой области, определяем область нашего "листа" на котором мы и будем рисовать(скажем 600х400 IU). Соответственно, при масштабировании мы увеличиваем размеры этого листа со всем его содержимым, т.е его размеры просто умножаем на ZoomFactor. Правильно мыслю? Тут ещё такой момент, обычно в программах, когда мы скролируем содержимое, размер скрола изменяется в соответствии с текущим масштабом, как это делается? :)
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как увеличить скорость отрисовки на canvas?

Сообщение MiniQ » 03.03.2014 12:44:35

Ну коли ТС все-же вернулся )), предлагаю создать новую тему по поддержке аппаратного ускорения в LCL http://freepascal.ru/forum/viewtopic.php?f=9&t=9721.
MiniQ
новенький
 
Сообщения: 81
Зарегистрирован: 28.01.2013 16:31:55

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 13:19:33

>>Тут ещё такой момент, обычно в программах, когда мы скролируем содержимое, размер скрола изменяется в соответствии с текущим масштабом, как это делается?
Глянь параметры которыми регулируется скроллбар, ими всё можно получить и размер и положение и т.д.
Ты что конкретно хотишь рисовать та?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Как увеличить скорость отрисовки на canvas?

Сообщение xterro » 03.03.2014 13:32:47

Ты что конкретно хотишь рисовать та?

Хочу сделать простой редактор эл. компонентов, т.е рисуем линии, прямоугольники, кружочки и т.д всё вместе это "компонент".
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как увеличить скорость отрисовки на canvas?

Сообщение zub » 03.03.2014 13:38:11

а куда далеше эти компоненты?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Пред.След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 227

Рейтинг@Mail.ru