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

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

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

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

Сообщение zub » 16.11.2016 01:15:59

alexey38, Alex2013
Про то что метафайл чтото ускоряет касаемо чистого вывода графики - сказки. Ускорение от него есть только в случае больших вычислений во время отрисовки, или как у ТС тормозных скриптов.
Я раньше это подозревал, сейчас проверил тестиком.
OpenGL driver info: NVIDIA Corporation GeForce GTX 970/PCIe/SSE2 4.5.0 NVIDIA 365.19
Draw 100000 random lines
Canvas: 102msec
GDIPlus: 281msec
AGG: 3992msec
OpenGL: 14msec
WMF: c:102msec d:103msec

Рисуется 1M рандомных линий. Голый канвас 102 милисекунды, метафайл 102 - создание и 103 - отрисовка созданого метафайла на канвас
тест тут http://sourceforge.net/projects/zcad/fi ... z/download
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Alex2013 » 16.11.2016 01:49:42

zub писал(а):alexey38, Alex2013
Про то что метафайл чтото ускоряет касаемо чистого вывода графики - сказки. Ускорение от него есть только в случае больших вычислений во время отрисовки, или как у ТС тормозных скриптов.
Я раньше это подозревал, сейчас проверил тестиком.

Ты просто не понял как я использую метофайлы и почему ...

Я почти не сомневался, что метофайлы работают точно такой скоростью и что и "чистая прорисовка " (честно говоря я даже подозревал, что метофайлы работают немного медленней ) моя беда в том, что у меня прорисовка совсем даже "не чистая" ... я использую для рисования пусть несложные но скрипты (кое где даже с примитивными расчетами с плавающей точкой ) и альтернативы использованию буферной коллекции метафайлов для ускорения работы всего две:
1 Делать коллекцию растровых "спрайтов" ...
2 Писать свой аналог метафайлов ....
Оба варианта затратны как по памяти так и по времени реализации .
Так что у меня в программе с прорисовка с буферизаций метофайлами совершенно точно работает существенно быстрее( причем настолько, что это очевидно без всяких тестов - не на порядок но явно в несколько раз )

Не веришь сравни на пример версию :arrow: FR0004_20_5_39_bin.7z и FR0004_20_5_46_4_bin.7z
Последний раз редактировалось Alex2013 16.11.2016 02:15:29, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение zub » 16.11.2016 02:14:54

>>Ты просто не понял как я использую метофайлы и почему ...
))
zub писал(а):Может пока будешь замерять за одно найдешь "узкое" место - оно у тебя на в выводе векторной графики совсем - или в скриптах или в руках))

тут кстати очепятка, на=не))
zub писал(а):я тебе уже говорил:
1 - прокладка межу "скриптами" и фактическим рисованием - чтобы организовать отрисовку как надо, а не как "слышится"

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

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

Сообщение Alex2013 » 16.11.2016 03:01:23

zub писал(а):>>Ты просто не понял как я использую метофайлы и почему ...
))
zub писал(а):Может пока будешь замерять за одно найдешь "узкое" место - оно у тебя на в выводе векторной графики совсем - или в скриптах или в руках))

zub писал(а):я тебе уже говорил:
1 - прокладка межу "скриптами" и фактическим рисованием - чтобы организовать отрисовку как надо, а не как "слышится"

Это какраз ты не понял.
Я тебе говорю про "прокладку" не потому что ты там выиграешь 50милисекунд, пусть даже проиграешь. А потому что это архитектурно правильно - разделить детали реализации частей программы.


Так это я вроде не тебе отвечал ... :wink:

Что до старого варианта программы ( взятого сейчас как основу для совсем другого проекта )про который я когда-то написал столь запомнившуюся тебе сентенцию "Принцип пишем как слышим рулит !" то ТАМ она была уместной ... потому что я не представляю себе "векторной иконки" или пиктограммы с более чем 200-ми элементами и размером более 200х200 (Все тестовые картинки там были сделаны с большим запасом ) а часть функционала была сделана с расчетом на "не очень далекое будущее " которое сейчас и наступило .

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

То есть например есть :
Код: Выделить всё
// Загрузка и показ изображения
Procedure Drw_LoadIMG (X,Y,x1,y1:LongInt;N:String);
Var
IM:TImage;
R,RS:Trect;
begin
If not FileExists(N) then exit;
Im:=TImage.Create(nil);
Im.Picture.LoadFromFile(N);
R:=RECT(X,Y,X1,Y1);
RS:=RECT(0,0,Im.Picture.Width,Im.Picture.Height);
CurCanvas.CopyRect(R,Im.Picture.Bitmap.Canvas,RS);
Im.Free;
end;

и есть

AddFunction(@Drw_LoadIMG,'Procedure Drw_LoadIMG(X,Y,x1,y1:LongInt;N:String);');

А в скрипте вообще все просто ...
Код: Выделить всё
...
begin
S:=GetParam('OP');
// парсинг команды  ...
Drw_LoadIMG(X,Y,FN);
end..

если это не "прокладка" то я уж совсем ничего не понимаю ... :idea:

Добавить свою "буферизацию команд" (и свой аналог WMF соответственно ) между выполнением списка скриптов и реальным рисованием тоже можно (это даже не очень сложно ) ...
Но метофайлы делают это проще и логичнее .. (Почти все обновление уместилось в одну процедуру )
За чем вообще скрипты прорисовки ? А затем, что ситуация может изменится противоположною.
Вот скрипт для наглядности ...
Код: Выделить всё
// Прорисовка звезды
..

Begin
S:=GetParam('OP');
...
x2:=X+ ((x1-x) div 2);
y2:=y+ ((y1-y) div 2);
x3:=X+ ((x1-x) div 3);
y3:=y+ ((y1-y) div 3);


Drw_Line(x,y3, x1,y3);
Drw_Line(x1,y3,x,y1);
Drw_Line(x2,Y,x,y1);
Drw_Line(x2,Y,x1,y1);
Drw_Line(x1,y1,x,y3);
end.


То есть очень простые функции могут рисовать непростую составную фигуру
(пятиконечная звезда без поворота разумеется фигура простая но как краткий и понятный пример годится )
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение zub » 16.11.2016 03:44:48

>> я когда-то написал столь запомнившуюся тебе сентенцию
До тебя так и недошло что подобные фразы неуместны нигде))

>>Что до разделения в "архитектурных целях" то разделение скрипты / программа
Никакое это не разделение, это вынос некоторого функционала из компайлтайм в ран тайм. На таком этапе развития от скриптов вреда больше чем пользы.

>>если это не "прокладка" то я уж совсем ничего не понимаю ... :idea:
Говоря про разделение я говорю примерно о
Скрипт-Внутреннее представление графики-Система отображения
Без всяких конкретик типа канвас или метафайл. Используешь gdi как систему отображения - используются метафайлы, используешь OpenGL - используются gl специфичные буфера.
Причем части программы должно быть возможно тусовать без изменений в других частях. Например вместо скриптов использовать другой источник графики, вместо канваса опенгл...

>>То есть например есть :
А должно быть чтото наподобии
Код: Выделить всё
Procedure Drw_LoadIMG (Dest:TDrawContext;X,Y,x1,y1:TCoordType;N:TYourString);
Var
  PImageDesk:^ImageDesk;
begin
  PImageDesk:=ImagesManager.FindLoadedImage(N);
  If PImageDesk<>nil then ImagesManager.DrawImage(Dest,X,Y,x1,y1,PImageDesk)
  else
  begin
   PImageDesk:=ImagesManager.LoadImage(N);
   If PImageDesk<>nil then ImagesManager.DrawImage(Dest,X,Y,x1,y1,PImageDesk)
  end;
end;

Т.е. разные моменты решаются в разных местах - откуда грузить диск-инет..., куда грузить битмап для канваса-текстура для OGL..., как выводить... Ну и естественно кэшировать, за лопатенье диска в онпаинт руки отрывать надо.
причем в скрипте данная функция должна быть зарегистрирована без Dest:TDrawContext зачем скрипту рисовать в другие места кроме как на область отображения, наверно ты это и решаешь курруанвасом.

>>Но метофайлы делают это проще и логичнее .. (Почти все обновление уместилось в одну процедуру )
Я тебе уже говорил что ты выбрал самый отстойный способ выделения объектов мышкой (Принцип пишем как слышим рулит, ага). Чтоб реализовать этот и многие другие моменты правильно (теже габариты определить) тебе понадобится информация о геометрии объектов в программе. Постоянно гонять для этого скрипты - медленно, метафайл прячет эту инфу внутри себя, недоберешся... Извиняй, в этом месте без нормальной "прокладки" никак

Добавлено спустя 22 минуты 43 секунды:
>>За чем вообще скрипты прорисовки ? А затем, что ситуация может изменится противоположною.
Скрипты так скрипты, это мало что меняет. Это всеголишь способ получить геометрию объекта в программу. Способ не лучше и не хуже других (хотя с учетом что ps мертвый, наверно всетаки хуже)(также нормальные люди предпочтут визуальные способы пополнения примитивов - нарисовал "звезду" линиями, добавил в "базу" используешь вдальнейшем как примитив)

зы. чето глядя на твой скрипт подозреваю, что потом когда появятся инструменты работы с чертежом - например "повернуть вокруг произвольной точки" в таком скрипте повернется только точка вставки звезды, сама звезда крутится небудет. Вообще с учетом преобразований объектов вся твоя скриптовая система летит к чертям, т.к. ты загнал пераметризацию объекта внутрь скрипта.
ИМХО правильно преобразовывать объекты без учатия скрипта, т.е. применительно к этой звезде в скрипте только определять количество вершин, а поворот-растяжение-положение без участия скрипта
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение Alex2013 » 16.11.2016 16:40:30

Ну что-ж спасибо за дельный совет ... и извини если временами не "в коня корм" у меня все-же не кад-система и чертежей в 3д не предвидится ...
:wink:(На самом деле я пишу "не как слышу" а "как могу" и могу я далеко не все ... да и сознаюсь лень часто мучает :oops: .) Но думать буду, темболее, что начал ( пока "бумажную") разработку новой части проекта "компоновщик".
Зы
Я вожусь со скриптами совсем не только потому что это "глубокая инкапсуляция" например геометрии .

А что-бы была возможность быстро и практически "на коленке" сделать новый визуальный (но это кстати не обязательно ) шаблон для почти любой технологии расширяющей стандартный HTML .. или вообще придумать что-то свое ... :idea: То есть как в классическом настольном компе есть материнка и платы расширения (могущие быть вообще "дикими" вроде платы овердрайв процессора, а в моем случае это может быть вызов внешних утилит вплоть до PHP перепроцессора или утилиты управления БД хотя это явно крайности вроде того-же овердрайва )
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение zub » 16.11.2016 23:09:17

Незачто, советы давать - не мешки ворочить))
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение IStukalov » 01.04.2022 14:09:54

Добрый день.
Реанимирую тему.
Собственно занялся изучением графики. Пока стандартными средствами Lazarus.
С помощью Canvas рисую графические примитивы (простой прямоугольник).
После его отрисовки, с помощью мышки двигаю его по площади. Собственно при движении влево и вниз мерцания нет, при движении вправо и вверх есть мерцания верхней линии либо боковой правой линии.

Вчера почитал многие вещи и попробовал разные рекомендации, не помогло.
Предложили в другом месте использовать: BGRABitmap. Сейчас изучаю на него документацию, но пока что не все там понятно, прозрачно и просто как в стандартном PaintBox.

Есть несколько вопросов:
1. Как то можно все таки убрать мерцание с помощью стандартных функций/процедур?
2. По какому принципу вообще рисуются геометрические фигуры, если я например даже их не заливаю? Т.е. в моем понимании должны были рисоваться только линии, которые соединяют точки, а такое впечатление, что рисуется вообще вся видимая область (отсюда и идет эффект мерцания) фон + плюс фигура.
3. Где-то можно почитать теорию реализации TCanvas в Lazarus? Т.е. интересует, как реально происходит взаимодействие фона и рисунков на нем?
IStukalov
новенький
 
Сообщения: 25
Зарегистрирован: 16.03.2022 14:35:43

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

Сообщение Shleps » 02.04.2022 19:33:37

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

А можно кусочек кода в студию?

В эпоху MS DOS для экономии процессора было обычным делом рисовать "резиновые" (т.е. подлежащие шевелению мышкой) объекты в режиме XOR. (Canvas.Pen.Mode:=pmXor;)
нарисовал раз - появилось, нарисовал ещё раз - исчезло - можно рисовать в новом месте.
Поскольку при рисовании ничего не стирается - то мелькание практически отсутствует (не считая муаровых эффектов при шершавом фоне).
Даже в случае прямого доступа в видеопамять в эпоху дос.

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

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

В эпоху многозадачных ОС напрямую поиграться с видеопамятью никто не даст, но рисовать на канвас буфера вместо панели, а потом вывести буфер одним махом вполне можно. Если рисование на канвас по какой-то причине долгое и муторное, то так еще и реакция приложения на проезжающие то нему окна улучшится.
Аватара пользователя
Shleps
постоялец
 
Сообщения: 194
Зарегистрирован: 14.06.2006 20:25:14

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

Сообщение Sharfik » 02.04.2022 22:42:15

IStukalov может поможет чем то viewtopic.php?f=32&t=9607 там в теме есть исходники. На чистом Canvas делал.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 760
Зарегистрирован: 20.07.2013 01:04:30

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

Сообщение IStukalov » 03.04.2022 09:29:35

Shleps
Кусочек кода движения?
Вот он:
Код: Выделить всё
procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin 
    ...
    PaintBox1.Canvas.Pen.Color := PaintBox1.Color; // берем цвет фона, чтобы затереть прямоугольник по старым координатам
    PaintBox1.Canvas.Rectangle(r.X, r.Y, r.X+r.dX,r.Y+r.dY);; // стираем старый прямоугольник
    r.X := X; //присваиваем новые координаты положения мыши
    r.Y := Y;

    PaintBox1.Canvas.Pen.Color := clRed; // указываем цвет прямоугольника
    PaintBox1.Canvas.Rectangle(r.X, r.Y, r.X+r.dX,r.Y+r.dY); // рисуем прямоугольник по новым координатам
    ...
end;

Т.е. тут все просто и примитивно. Также пробовал вместо последних двух строчек кода вызывать процедуру прорисовки PaintBox1Paint(Sender: TObject);. Но это ничем не помогло.

Sharfik
Скачаю, посмотрю сегодня.
IStukalov
новенький
 
Сообщения: 25
Зарегистрирован: 16.03.2022 14:35:43

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

Сообщение Shleps » 03.04.2022 10:34:21

Можно попробовать с буфером (кусок из моего визуализатора, только у меня вместо паинтбокса рисуется на TPanel)

Var BufBitMap:TBitMap;
...
BufBitMap:=TBitMap.Create;
...
OCW:=PaintBox1.ClientWidth;
OCH:=PaintBox1.ClientHeight;
BufBitMap.SetSize(OCW,OCH);
BufBitMap.Pen.Color := PaintBox1.Color; // берем цвет фона, чтобы затереть прямоугольник по старым координатам
BufBitMap.Canvas.Rectangle(r.X, r.Y, r.X+r.dX,r.Y+r.dY);; // стираем старый прямоугольник
r.X := X; //присваиваем новые координаты положения мыши
r.Y := Y;

BufBitMap.Canvas.Pen.Color := clRed; // указываем цвет прямоугольника
BufBitMap.Canvas.Rectangle(r.X, r.Y, r.X+r.dX,r.Y+r.dY); // рисуем прямоугольник по новым координатам

...
в OnPaint вот такое
PaintBox1.Canvas.CopyRect(Rect(0,0,PaintBox1.ClientWidth,PaintBox1.ClientHeight),BufBitMap.Canvas,Rect(0,0,PaintBox.ClientWidth,PaintBox.ClientHeight));

и еще нужная команда - PaintBox1.Invalidate
я так понял, что именно она объясняет, что все нарисованное уже некодиционно и вызывает OnPaint
попытки просто ляпать буфер на элемент управления, насколько я помню к желаемому эффекту не приводили
если потом надщо будет предусмотреть вывод на принтер будет ещё чуть сложнее
Аватара пользователя
Shleps
постоялец
 
Сообщения: 194
Зарегистрирован: 14.06.2006 20:25:14

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

Сообщение iskander » 03.04.2022 13:12:06

Емнип в LCL рисование на канве должно происходить внутри обработчика OnPaint.

Попробовал сделать маленький пример.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

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

Сообщение zub » 03.04.2022 14:01:08

Подход стереть старое и нарисовать новое - не пройдет на насыщенных картинках, там где примитивы накладываются друг на друга
Я бы сохранял картинку без "динамического" примитива в прошлом кадре, восстанавливал ее в новом и рисовал примитив в новом месте

При рисовании вне события отрисовки не будет работать штатный метод двойной буферизации. Кроме того этот способ не работает в qt5, в qt4 требует дополнительной настройки контрола. Рекомендуется рисовать на канве внутри OnPaint, перерисовку вызывать Invalidate
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

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

Сообщение IStukalov » 03.04.2022 19:30:26

Shleps
Попробовал, получил странный эффект. Черный экран, белый прямоугольник. При передвижении прямоугольника, ловлю мерцание экрана теперь.

iskander
Да работает без мерцания. Логику понял. Ну и понял, что неправильно делал прорисовку в своем коде (делал по сути по примерам найденным в инете).

zub
У меня не планируется насыщенных картинок.

Собственно более корректный код взял у iskander. Далее по нему буду прорабатывать то, что мне требуется. Всем спасибо за консультацию и помощь :)

Добавлено спустя 17 минут 19 секунд:
Ну и собственно у себя, убрал одну строчку и добавил ту, которую изначально не делал, мерцание пропало. Еще раз всем спасибо :)
IStukalov
новенький
 
Сообщения: 25
Зарегистрирован: 16.03.2022 14:35:43

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru