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

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

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

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

Сообщение Mirage » 03.03.2014 20:54:03

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


Не знаю точно как в LCL, но в LCL если TImage большого размера положить в TScrollBox, то при прокрутке все замечательно перерисовывается. Остается лишь рисовать что нужно на TImage.
Почитав тему далее, тоже рекомендовал бы использовать OpenGL. Немного освоиться с матрицами преобразования и можно будет рисовать на порядок больше элементов. А если сделать оптимизированный рендер (что, правда, непросто), то и на несколько порядков. Хотя все можно сделать и в софте.
Есть ведь еще такие либы как AggPas.

debi12345 писал(а):Странно что использование безметодового (абстрактного) класса (=интерфейса) приводит к таким тормозам. Скорее всего дело именно в "безметодовости" (невозможности прописать VMT-зависимости на этапе компиляции).


Дело наверное таки в подсчете ссылок.

ABSTRACT - в-о-о-т где его применение оказывается ! Не пользовался ранее - возьму на заметку :)


Аххахах, это пять! :mrgreen:

zub, ответил в новой теме
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение debi12345 » 03.03.2014 21:10:10

Дело наверное таки в подсчете ссылок.

Для CORBA-типа они считаются автоматом (не нужны AddRef & Co) ? Это точно ?

Аххахах, это пять!

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

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

Сообщение CriDos » 03.03.2014 23:25:28

В своём проекте использую BGRABitmap+некоторую оптимизацию.
Довольно долго изучал возможные варианты, включая OpenGL, ZenGL и стандартные инструменты, но решил остановиться именно на такой связке.
В общей сложности, удалось добиться отличных результатов времени расчётов и отрисовки огромного к-ва элементов в зоне видимости.
Вот небольшая демонстрация:
ScreenDemo Win
Windows x32 Binary

ScreenDemo Lin
Linux (Mint) x32 Binary (запускать из терминала)

Сборка проводилась из стандартной конфигурации Lazarus 1.0.14, с отключенной отладочной информацией + BGRABitmap.
Единственный недостаток который я так (пока) и не смог побороть, это жуткие тормоза при отрисовке в KDE, вне зависимости чем рисую (BGRABitmap или стандартный канвас).

Сейчас пытаюсь реализовать данные наработки в Qt 5.х, дабы было общее представление о различии производительности.
CriDos
новенький
 
Сообщения: 11
Зарегистрирован: 07.05.2013 11:06:10

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

Сообщение debi12345 » 04.03.2014 00:23:13

Хотя что-то я стормозил - тестировал-то на 10млн вызовов. И только на них набралось 5% На 30-ти вообще нет никакой разницы.

Тьфу черт - опять сглючил - в примере же не вызов из вызова и далее по цепочке (что считается "x PWR y"), а один и тот же вызов многократно, много итераций - исключительно для увеличения точности измерений. Так что 5% на молотильный вызов остаются в силе, и импакт от виртуальности зависит исключительно от веса полезного кода. Численно на примере подтвердить это трудно, разве что рекурсивом - однако рекурсив оптимизируется, что искажает измерения.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

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

Сообщение zub » 04.03.2014 01:16:04

Чето опять не то)) проигрыш 5% на идентичном синтетическом коде, состоящем почти только из вызовов. считаем что виртуальных вызовов столькоже сколько и через указатель на функцию - ведь наши методы рисования будут отличаются только способом скрытия реализации. Такчто больше уже небудет. Стоит добавить чуток полезного кода и 5% превратятся в 0.000005%. Как говорится на эти 2 процента и живем))
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение debi12345 » 04.03.2014 01:38:37

Чето опять не то)) проигрыш 5% на идентичном синтетическом коде, состоящем почти только из вызовов. считаем что виртуальных вызовов столькоже сколько и через указатель на функцию - ведь наши методы рисования будут отличаются только способом скрытия реализации. Такчто больше уже небудет.
Надо также учесть код настройки стека на входе и выходе функции, который может быть увесистее, чем молтильный код (в нашем примере - несомненно увесистее)

Такчто больше уже небудет.

Будет накручиваться по 5% в каждом случае, когда виртуальная функция вызывает другую молотильную виртуальную функцию... В случае немолотильной будет меньше 5%.
Для случая коротких функций возьмем к примеру среднее 1%. При 50-ти последовательных вызовах маемо импакт 64%. 10 вызовов = 10%. 15 вызовов = 16%. 20 вызовов = 22%.

Добавлено спустя 12 минут 22 секунды:
Опять неверно. Вы правы, действительно 5% - верхний потолок, сколько бы последовательных вызовов не было. Не процент на депозите же считаем :) Однако это плохая новость для использования интерфейсов с 10кратным импактом.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

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

Сообщение Mirage » 04.03.2014 11:51:09

debi12345 писал(а):Для CORBA-типа они считаются автоматом (не нужны AddRef & Co) ? Это точно ?


Не скажу за Corba-типы, но для интерфейсных ссылок осуществляется их подсчет (вызываются addref/release) и даже вызов destroy когда ссылки кончаются.

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


Удобства интерфейсов не получить, т.к. интерфейсы еще и делегироваться могут (ключевое слово implements).

CriDos, впечатляет. Может, расскажешь про оптимизации?
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение CriDos » 04.03.2014 13:41:17

Mirage писал(а):CriDos, впечатляет. Может, расскажешь про оптимизации?

Оптимизации которые серьёзно повысили производительность относительно рисования в лоб:
1) Рисуем только то, что видим.
2) При каждом рисовании, создаётся внутренний буфер для каждого состояния сложных и повторяющихся фигур (круг например+сглаживание или отсутствие) с учётом масштабов и других параметров, и в дальнейшем оные просто вставляются в основной буфер при отрисовке каждого элемента, что очень сильно повлияло на общую скорость отрисовки.
3) В планах улучшить данный способ, до создания внутреннего буфера для каждого элемента, при обращении к оному, и перерисовывать буфер при изменении состояний элемента.
В итоге, мы будем рисовать объекты из индивидуального буфера элементов, и перерисовывать только те элементы, с которыми взаимодействуем или которые меняют визуально своё состояние.
Но это уже после экспериментов с Qt.

В общем, оптимизации на уровне "Новичок в графике", берущий идеи из квантовой механики и окружающей среды в целом :lol:

Добавлено спустя 2 часа 31 минуту 47 секунд:
xterro писал(а):Например, сейчас я сетку рисую во вложенном цикле. Была мысль заменить два цикла на один, но отрисовывать вместо точек dash line с большим расстоянием между точками. Как считаете, это увеличит производительность?

Посмотрел текущую реализацию вашей сетки.
Зачем вообще линии использовать? Есть же прямой доступ к пикселям Canvas.Pixels[] или BGRABitmap.SetPixel()!
Вот например моя функция отрисовки сетки:
Код: Выделить всё
procedure THiSDK.DrawGrid;
var
  OffsetGridSDK, MaxGridSDK: TPoint;
  iGor, iVer: Integer;
begin
  if bEnableVisibleGrid then
  begin
    OffsetGridSDK.x := trunc(OffsetXY.x / GridStep / Scale);
    OffsetGridSDK.y := trunc(OffsetXY.y / GridStep / Scale);

    MaxGridSDK.x := trunc(Width_SDK / GridStep / Scale) + OffsetGridSDK.x;
    MaxGridSDK.y := trunc(Height_SDK / GridStep / Scale) + OffsetGridSDK.y;

    for iGor := OffsetGridSDK.x to MaxGridSDK.x do
    begin
      for iVer := OffsetGridSDK.y to MaxGridSDK.y do
      begin
        Buffer.SetPixel(trunc(iGor*GridStep*Scale) - OffsetXY.x,
                        trunc(iVer*GridStep*Scale) - OffsetXY.y, BGRABlack);
      end;
    end;
  end;
end;
CriDos
новенький
 
Сообщения: 11
Зарегистрирован: 07.05.2013 11:06:10

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

Сообщение debi12345 » 04.03.2014 16:30:17

Зачем вообще линии использовать? Есть же прямой доступ к пикселям

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

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

Сообщение zub » 04.03.2014 16:40:06

>>1) Рисуем только то, что видим.
С виду не скажешь, либо процедура проверки видимости не тороплива((
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение CriDos » 04.03.2014 16:42:07

debi12345, не знал об этом, нужно будет проверить:)

Добавлено спустя 11 минут 33 секунды:
zub писал(а):С виду не скажешь, либо процедура проверки видимости не тороплива((

Ну в случае обработки большого к-ва объектов (свыше 5000+), разница очень хорошо заметна.
А в качестве проверки, в процедуре отрисовки для каждого объекта использую функцию RectInArea:
Код: Выделить всё
function THiSDK.RectInArea(rRect1,rRect2:TRect): boolean;
var
  hTemp,hRgn1,hRgn2: HRGN;
  CombineResult: LongInt;
begin
  Result := False;

  hTemp:=CreateEmptyRegion;
  hRgn1:=CreateRectRgnIndirect(rRect1);
  hRgn2:=CreateRectRgnIndirect(rRect2);

  CombineResult := CombineRgn(hTemp,hRgn1,hRgn2,RGN_AND);
  if CombineResult in [SimpleRegion, ComplexRegion] then Result := True;

  DeleteObject(hTemp);
  DeleteObject(hRgn1);
  DeleteObject(hRgn2);
end;


Раньше использовал альтернативную реализацию RectInArea:
Код: Выделить всё
function RectInArea(Area, oRect: TRect): boolean;
var
  hRegion: HRGN;
begin
  Result := False;
  hRegion := CreateRectRgnIndirect(Area);
  if hRegion <> 0 then
    try
      Result := RectInRegion(hRegion, oRect);
    finally
      DeleteObject(hRegion);
    end;
end;

Но как оказалось, она платформозависимая :)
CriDos
новенький
 
Сообщения: 11
Зарегистрирован: 07.05.2013 11:06:10

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

Сообщение Sergei I. Gorelkin » 04.03.2014 17:13:28

Если оба региона прямоугольные, то достаточно функции types.intersectrect. Она как бы немного быстрее создания и удаления трех GDI объектов.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

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

Сообщение CriDos » 04.03.2014 17:54:52

Sergei I. Gorelkin писал(а):types.intersectrect

Забыл указать. :)
Её я и стал использовать после платформозависимого варианта, пока не выяснилось, что в linux системах данная функция работает не так как в windows.
А так как данная функция участвует в реализации селекции объектов, возникли проблемы из за этого самого нюанса работы под различными ОС.
В качестве компромисса и была реализована финальная вариация RectInArea.
Однако что то я не додумался воткнуть intersectrect отдельно в проверку вхождения объектов в зону видимости...
Вроде быстрее на пару % отрабатывает :)
Ну а для селекции, придётся оставить текущую реализацию RectInArea...
CriDos
новенький
 
Сообщения: 11
Зарегистрирован: 07.05.2013 11:06:10

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

Сообщение Mirage » 04.03.2014 18:53:51

Хм, но ведь чтобы проверить входит ли один прямоугольник в другой, не нужно WinAPI? Да и от ОС это никак не зависит. :shock:
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение CriDos » 04.03.2014 21:18:37

Вру, от ОС не зависит, забываю уже об нюансах разработки :lol:
Проблема оказалась в невозможности определения некоторых вариантов вхождения части прямоугольника в другой.
Например:
Изображение
Код: Выделить всё
var
  r1,r2, rTemp: TRect;

begin
  r1:=Rect(424,65,370,96);
  r2:=Rect(329,49,390,117);
  ShowMessage(BoolToStr(IntersectRect(rTemp,r1,r2)));

функция IntersectRect вернёт: false

А по поводу нюанса из предыдущего сообщения, это было связанно с работой функции CombineRgn.
Под Linux она работала не так как требовалось, и пришлось смастерить маленький костыль:
Код: Выделить всё
    //Костыль для Linux (RectInArea -> CombineRgn)
    if y < y2 then rFrame := Rect(x,y,x2,y2)
    else rFrame := Rect(x2,y2,x,y);
CriDos
новенький
 
Сообщения: 11
Зарегистрирован: 07.05.2013 11:06:10

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru
cron