Как ускорить прорисовку векторной графики ?

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

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

Re: Как ускорить прорисовку векторной графики ?

Сообщение olegy123 » 11.11.2016 00:07:26

А что мешает по Z координате сортировать?
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 11.11.2016 00:21:04

Ничего. в 2д случае это не координата как таковая, а порядок отрисовки
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение olegy123 » 11.11.2016 00:39:04

Понял..
На TBitmap-е рисуете графику, потом BitBlt обновляете.

Чё то думал, что на панели расположены были контролы.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 11.11.2016 01:13:11

>>На TBitmap-е рисуете графику, потом BitBlt обновляете.
У меня не получилось использовать TBitmap. Подробностей не помню, но битмап у меня получался в озу, а не в видеопамяти, соответственно запоминание-восстановление изображения приводило к ненужному перегону мегобайтиков между процом и видюхой (у ТС судя по всему проблема таже, раз ему это чувствительно и жалуется на зависимость времени от разрешения). Потыкавшись написал свой контрол для этих целей на основе LCLной реализации GDI, пусть кривой но зато с полным контролем процесса отрисовки.
Кстати GDI в LCL кроссплатформенно, а вот метафайлы емнип нет, Alex2013 чтоб потом для тебя сюрпризом небыло, когда под линь компильнуть решишь))
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение alexey38 » 11.11.2016 10:38:33

Alex2013 писал(а):Просто TMetafile (+ Еще и скрипты) неизбежное зло с которым более мене понятно что делать (или не делать если все более или менее но утраивает )... Вот явно непропорциональные тормоза при увеличении разрешения рабочего поля напрягают. (Тем боле что ничего похожего во многих программах нет )

прорисовка элементов в TMetafile и из TMetafile в общий TMetafile, А это зачем ? :roll: У меня цикл сразу выводит отдельные "Metafile" на теневой битмап который потом копируется на канвас ПаинтБокса ... Хотя если подумать возможно будет реально быстрее ( за счет того, что Metafile может не иметь заранее заданных границ и не передает лишних "пустых "данных) . Но мне показалась, что если я буду рисовать метофайлы на прямую то будет видно как и куда "процесс пошел " что не есть хорошо .


У нас двойной вывод элементов в TMetafile и из TMetafile в общий TMetafile и далее в TBitmap используются для того:
1. Metafile элемента формируется один раз до изменения конкретного элемента (рисование примитивов один раз за весь период работы программы).
2. На этапе сборки общего Metafile идет отсеивание элементов, не входящих в видимую область. Работает быстро, т.к. по сути Metafile - это коллекция векторных примитивов, и добавляя в коллекцию другую готовую коллекцию никакой перерисовки и не происходит.
3. На этапе вывода общего Metafile в теневой Bitmap осуществляется масштабирование и обрезание строго по границам экрана.

Если все работало быстро на старых компах на разрешениях (1280*1024, 1600*1200 и более высоких), то на современных компах на самых больших мониторах число точек больше всего примерно в 4 раза, то и никаких особых тормозов тоже не наблюдается. Мы еще лет 7 тому назад в одном проекте работали с видеокартой AMD, к которой было подключено 6 мониторов по 1920*1080 повернутых на 90 гр (общее разрешение 6480 на 1920). Особых тормозов не было еще тогда, не говоря о сегодняшнем железе. Да и откуда им быть. Даже на таком разрешении размер TBitmap всего 48 Мб (4 байта на пиксель) - это копейки для оперативной памяти при частотах в несколько ГГц.

Поэтому тормозить операции с Bitmap не могут по определению, искать там выигрыш в микросекунды или даже в миллисекунды бессмысленно. Тормозить может только вывод векторной графики. Если у Вас масштаб не меняется часто, а графических примитивов очень и очень много, то элементы можно из элементного TMetafile можно переводить в TBitmap.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 11.11.2016 10:47:41

Данная схема либо требует от графической системы поддержки трансформаций, либо подходит только для статичных "картинок". Соглашусь с Alex2013 в векторном редакторе, где всё постоянно зумится и панится общий метафайл лишний - очень большая вероятность того что при следующей отрисовке он будет неактуален, например в кадр попадет чтото что раньше было невидимо и наоборот, ранее видимые примитивы уйдут за преджелы экрана
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение alexey38 » 11.11.2016 13:01:08

zub писал(а):Данная схема либо требует от графической системы поддержки трансформаций, либо подходит только для статичных "картинок". Соглашусь с Alex2013 в векторном редакторе, где всё постоянно зумится и панится общий метафайл лишний - очень большая вероятность того что при следующей отрисовке он будет неактуален, например в кадр попадет чтото что раньше было невидимо и наоборот, ранее видимые примитивы уйдут за преджелы экрана


Я как раз про векторный редактор и говорю. Общий метафайл, как посредник перед общим битмапом - это не панацея, но нам было так проще, а возможно было даже быстрее (делали 15 лет тому назад, всех нюансов уже не помню, пробовали разные варианты, остановились на этом). Вывод метафайла в метафайл практически не занимает времени, т.к. как таковой отрисовки при этом не происходит, происходит копирование списка графических примитивов из одной коллекции в другую.

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

Я говорю не о теоретических рассуждениях и предположениях, а о реальной практической реализации векторного редактора и векторного визуализатора. Этот путь был нами выбран на основании сравнения разных вариантов. Это вариант оказался самым быстрым, т.к. в те времена быстродействие было критически важным.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 11.11.2016 14:00:32

Ок пусть будет общий метафайл. Но это только технический момент - способ скармливания большого числа примитивов в GDI, причем не везде он присутствует.
Отталкиваться надо от алгоритмов, а не от деталей реализации
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение olegy123 » 11.11.2016 16:07:42

про какой метафайл вы говорите?
про TMetafile? А он еще используется?
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как ускорить прорисовку векторной графики ?

Сообщение serbod » 11.11.2016 18:52:24

Пересечения легко вычислять по пикселям:
https://habrahabr.ru/post/202888/
https://code.tutsplus.com/tutorials/pix ... tive-10862
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 11.11.2016 19:06:18

Операции с пикселями на CPU - главный тормоз. Будте любезны на GPU в шейдеры, если есть такая нужда
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение Alex2013 » 12.11.2016 15:58:32

Вчера ушел в глубокий офлайн и сделал два полезных дела:
1 Выделил работу с метафайлами в отделенную процедуру.
Код: Выделить всё
// Быстрая прорисовка призвольного фрагмента DrawList
// на  CurCanvas
procedure TRF1.FastDrawFig(PosInList,FigCount:LongInt);
var I:Integer;
     MC:TMetafileCanvas;
     MyMetafile: TMetafile;
     SaveCanvas:TCanvas;
     FADD:Boolean;// Флаг для наглядого представления  условий
     Const
       FMD:Boolean=True; // Флаг первого запуска
begin
// Ограничения
   if DrawList=NIL then exit;
   if DrawList.Count = 0 then exit;
   If FigCount < 0 then exit;
   If PosInList < 0 then exit;
   If PosInList > DrawList.Count-1  then exit;
   If PosInList+FigCount > DrawList.Count  then
                 FigCount:= DrawList.Count-PosInList;
   //Если   список не пуст ...
   SaveCanvas:=CurCanvas;
// проверка и создание MetaDrawList и ShadowDrawList ;
     If MetaDrawList = Nil Then MetaDrawList:=Tlist.Create ;
     If ShadowDrawList  = Nil Then Begin ShadowDrawList:=TStringlist.Create ;
                                         ShadowDrawList.Text:=DrawList.Text;
                                   end;
// Главный цикл
  For I:=PosInList TO PosInList+FigCount -1 DO
    Begin
    FADD :=FmD Or  (I > ShadowDrawList.Count-1);
    FADD := FADD Or  (I > MetaDrawList.Count-1);
    FADD := FADD Or  (ShadowDrawList[I] <> DrawList[I]);
   If FADD Then
     begin
     // Инициализирую метафайл ...
     MyMetafile := TMetafile.Create;
     MC:= TMetafileCanvas.CreateWithComment(MyMetafile, BufBMP.Canvas.handle,
      'Author', 'Made This');
      CurCanvas:=MC;//Перенаправляю Canvas
        DrawFig(-1,DrawList[i]);//Рисую фигуру
      MC.Free; //! Обязательно очищать MetafileCanvas  преред "клонированием" ...

      CurCanvas:=SaveCanvas;// Востанавливаю Canvas...

      // Доплнение изменение списка MetaDrawList
      //----------------------------------------
      If FmD then MetaDrawList.Add(MyMetafile)
       // Первый раз безусловное добавление
        else
           if I<=MetaDrawList.Count-1 then
             // Простая замена в границах списка
                begin
                  TMetafile(MetaDrawList[i]).Free;
                  MetaDrawList[i]:=MyMetafile;
                end
           else
         if  I=MetaDrawList.Count  then
             // Добавить в конец списка если на единцу бльше
             MetaDrawList.Add(MyMetafile);
       //=================================================
      CurCanvas.Draw(0,0,TMetafile(MetaDrawList[i])); //draw
     end else
   begin
     CurCanvas.Draw(0,0,TMetafile(MetaDrawList[i])); //fast draw
     end
    end ;
   FMD:=False ;// Сброс флага
   ShadowDrawList.Text:=DrawList.Text; // Сбросить различия
   Listbox1.Items.Text:=DrawList.Text; //? Освежить видимый список комманд
end;

2 Окончательно подавил мерцание при рисовании мышкой...
И вот с этим возникли странные трудности ( Пока не нашел ничего лучшего чем сделать еще один буфер )
Код: Выделить всё
// Защита от мерцания
If b1=nil then B1:=TBitmap.Create;
B1.Assign(BufBMP);// сохраняю теневой битмап
//кстати это еще один способ быстрого копирования между битмапами
CurCanvas :=BufBmp.Canvas;
FastDrawFig(DrawList.Count-1,1);// рисую на нем ...
ReStoreBuf; // "Восстанавливаю" картинку ( то есть рисую в месте с фигурой )
CurCanvas:=PaintBox1.Canvas;
CurCanvas.Refresh;
BufBMP.Assign(B1); // ...и командую "тень знай свое место "... :wink:
b1.FreeImage;
//--------------------------------------

Тормозов вроде не наблюдается ... но изначально я думал сделать значительно менее ресурсоёмко . :idea:
1 Включить для фонового битмапа mpNotXor
2 Нарисовать фигуру на фоновом битмапе ( именно на фоновом !...дабы сей замечательный процесс видно не было ...)
3 Вывести на экран ...(ReStoreBuf; )
4 Снова нарисовать фигуру на фоновом битмапе (то бишь затереть то что было нарисовано первым проходом )
5 Вернуть для фонового битмапа mpСоpy ...
...и "Ку вам товарищ четланин" ничего не фурычит как ни бился ...
:roll: Посему вопрос, какого лешего это вообще даже в принципе может не работать :?: :!: Там же все "тупо как сибирский валенок" ... :evil:
Еще вариант нарисовать фигуру на пустом битмапе как "спрайт " и сложить фоновым но это уже явный тормоз (при создании битмапа его нужно ресайзить и/или чистить )

Добавлено спустя 53 минуты 12 секунд:
zub писал(а):Ок пусть будет общий метафайл. Но это только технический момент - способ скармливания большого числа примитивов в GDI, причем не везде он присутствует.
Отталкиваться надо от алгоритмов, а не от деталей реализации

Я думаю что все дело как раз в особенностях реализации .
Например у меня есть идея рисовать на метофалах все с нуля координат (добавляя смещение дополнительным параметром ).
Вроде "деталь реализации" но логику она может изменить очень сильно.

Добавлено спустя 1 час 2 минуты 33 секунды:
zub писал(а):>>На TBitmap-е рисуете графику, потом BitBlt обновляете.
Кстати GDI в LCL кроссплатформенно, а вот метафайлы емнип нет, Alex2013 чтоб потом для тебя сюрпризом небыло, когда под линь компильнуть решишь))


:idea:
Почему это ? Я использую модуль MyMetaFile от сюда http://wiki.freepascal.org/TMetafile_/_ ... leCanvas...
Гм действительно "only works on windows" но возможно это верно для старой версии лазруса (Там многое из того что сейчас вполне работает даже не компилировалось )...

Да и вообще это не единственная реализация (я даже где-то в дебрях LCL что-то похожее видел )
Последний раз редактировалось Alex2013 13.11.2016 15:46:55, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2957
Зарегистрирован: 03.04.2013 11:59:44

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 12.11.2016 23:47:26

>>1 Выделил работу с метафайлами в отделенную процедуру.
>>2 Окончательно подавил мерцание при рисовании мышкой...
Ты собираешся постить на форуме каждый чих? Для этого есть комменты к комитам системы контроля версий.
Фигово ты както выделил - какието глобальные переменные остались

>> но возможно это верно для старой версии лазруса
)) метафайлы - часть GDI, их нет нет под линуксом.

>>Да и вообще это не единственная реализация
Это не реализация а интерфейс к функциям gdi
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как ускорить прорисовку векторной графики ?

Сообщение Alex2013 » 13.11.2016 15:26:44

zub писал(а):Ты собираешся постить на форуме каждый чих? Для этого есть комменты к комитам системы контроля версий.
Фигово ты както выделил - какието глобальные переменные остались

Не каждый, а только на сабжевую тему ...
(И есть мысль что моя "наскальная живопись" может кому-то немного помочь ... А тот код, что я постил сюда ранее слишком уж "локальный"(привязан к моей программе ) чтобы в нем было просто разобраться .(Эта версия тоже не лишена "локальности" но факт что она значительно понятнее)

Что до второй части то я запостил ее просто для того чтобы не создавать новой темы из за такой ерунды .
(Да и близко довольно к теме : мерцание нужно победить по возможности не теряя скорости )
Зы
метафайлы - часть GDI, их нет нет под линуксом.

И что эмулировать на уровне канваса никак нельзя ? :roll: (Там же просто запись команд в формате WMF вместо реального рисования )
Alex2013
долгожитель
 
Сообщения: 2957
Зарегистрирован: 03.04.2013 11:59:44

Re: Как ускорить прорисовку векторной графики ?

Сообщение zub » 13.11.2016 15:54:52

>>И что эмулировать на уровне канваса никак нельзя ? :roll: (Там же просто запись команд в формате WMF вместо реального рисования )
Тебе и карты в руки))
http://msdn.microsoft.com/en-us/library/cc250370.aspx
http://wvware.sourceforge.net/caolan/ora-wmf.html
http://www.symantec.com/avcenter/refere ... format.pdf
>>(Да и близко довольно к теме : мерцание нужно победить по возможности не теряя скорости )
Дак оно прекрасно побеждается без потерь производительности. Такими кусками кода ты общаешся сам с собой. Есть проблема - делаешь минимальную демку ее демонстрирующую
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru