Russian Qt Forum
Декабрь 10, 2022, 11:59 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Долгое рисование  (Прочитано 2793 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июнь 21, 2021, 11:31 »

Добрый день

Возможно "пользовательский интерфейс" - более подходящий раздел, ну ладно.
Определимся с "долго", конкретный пример: рисуется 25K объектов, обновление одного окна занимает примерно 1.6 сек, это уже затрудняет активность юзверя.

Вечный вопрос  "как быстрее" здесь не стоит, размер данных принципиально не ограничен, 25К работает? А 250К? (как в старом анекдоте про бензопилу). Ну и само собой "гуй не должен замерзать".

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

Вопрос 2: а что собсно делать если отрисовка не усспевает? Полагаем что после отрисовки каждого (из 25К) объекта вызывается ф-ция IsInterrupred() (достаточно быстрая), без нее все равно не обойтись. И вот она вернула true. Дальше что?

Спасибо
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 562


Просмотр профиля
« Ответ #1 : Июнь 21, 2021, 13:28 »

Вопрос имеет архитектурный подтекст.
Как минимум, имеется несколько независимых этапа (можно выделить и больше):

- преобразование исходных данных в элементы отображаемой сцены,
- преобразование элементов сцены в данные для конвейера OpenGL,
- преобразование данных для конвейера OpenGL в кадр.

Эти этапы можно (нужно) выполнять независимо друг от друга.
При этом нет необходимости производить отображение при каждом элементарном изменении исходных данных.
На каждом этапе можно (нужно) забирать только изменения с предыдущего этапа (например, очередь изменений).
При этом события можно "проредить" (например, создание/удаление объекта и последовательное изменение одного и того же свойства и т.д.).

В OpenGL есть трудности с разделением функциональности по подготовке данных для конвейера и формированием кадра.
Если разделить все этапы, то "замерзание" GUI будет зависеть только от последнего этапа формирования кадра. А он будет зависеть от выбранной стратегии отображения - использования функциональности разных версий OpenGL, реализации шейдерных программ и т.п.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 21, 2021, 14:07 »

Как минимум, имеется несколько независимых этапа (можно выделить и больше):
...
Насколько понял, Вы говорите о "грамотной архитектуре рисования". Что, конечно, всегда  интересно (с удовольствием приму участие в обчуждении), но здесь речь не об этом. Полагаем что какое-то рисование есть/имеется, насколько оно быстро/оптимально - др вопрос, в любом случае найдется такой объем данных что скорость отрисовки не успеет за активностью юзера. В этой теме хотелось бы поговоритт как отрабатывать такую ситуацию
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 562


Просмотр профиля
« Ответ #3 : Июнь 21, 2021, 15:20 »

Полагаем что какое-то рисование есть/имеется, насколько оно быстро/оптимально - др вопрос, в любом случае найдется такой объем данных что скорость отрисовки не успеет за активностью юзера. В этой теме хотелось бы поговоритт как отрабатывать такую ситуацию

А что выносить в поток-то тогда)?
Основной профит здесь в "прореживании" и "группировке" событий. Если нет независимых этапов, то нечего и "прореживать".
Можно хоть миллион потоков сформировать, но, если поток отображения будет их ожидать, то отрисовка и взаимодействие с юзером будет тупить.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июнь 21, 2021, 16:11 »

Ладно, немного отвлечемся от темы, простой пример: юзер, всего-навсего, выбрал объект из списка (selected), нужно нарисовать его bounding box. И.. для примера выше рисуем все 25К объектов Плачущий Ну конечно на событиях (может он непрерывно выбирает), но возможности что-то "дорисовать" нет, каждая новая отрисовка начинается "с нуля" и будет молотить все. Поэтому я с сомнением отношусь к "прореживанию" и "группировке" Улыбающийся

Вернемся к теме
а что собсно делать если отрисовка не усспевает? Полагаем что после отрисовки каждого (из 25К) объекта вызывается ф-ция IsInterrupred() (достаточно быстрая), без нее все равно не обойтись. И вот она вернула true. Дальше что?
Лично я не вижу др решения кроме как:

- вывести на экран то что успели (swapBuffers) и выйти (вон) из метода рисования. Это можно с успехом делать в главной нитке. Очевидно такое рисование "огрызков" не впечатляет, но лучшего не видно, если ничего не выводить, то все просто "мэртво" при неуспевающей перерисовке.

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

Еще одна проблема - что писать в ф-ции IsInterrupted() ? Здесь 2 ситуации, первая - драг, очевидна: проверить сдвинулась ли мыша или была отпущена. К сожалению, и здесь проблемы (c QCursor::pos, создам тему об этом)

Второй случай - просто "регулярное" обновление, здесь хужее. Рисование в процессе, и тут юзер чего-то нажал (клаву или мышь). Выходить надо, иначе "гуй заморожен". Но нажатие далеко не всегда ведет к обновлению окон, активный юзер получает эффект "конвульсий" UI Плачущий  Впечатление что "вынос в поток" эту проблему решает (прерывается при следующем update()), как думаете? Но нырять в отдельную нитку - ну очень не хочется, ничего хорошего об этом не пишут.

Насколько верны мои соображения ?

Да, вот раньше бывало "настоятельно рекомендовали" - а сейчас нет  Улыбающийся
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 562


Просмотр профиля
« Ответ #5 : Июнь 21, 2021, 21:16 »

Вопрос 2: а что собсно делать если отрисовка не усспевает? Полагаем что после отрисовки каждого (из 25К) объекта вызывается ф-ция IsInterrupred() (достаточно быстрая), без нее все равно не обойтись. И вот она вернула true. Дальше что?

Если в OpenGL отображать каждый элемент отдельно, то никаких ресурсов не хватит). Важным является отображение всей сцены за минимальное количество обращений к контексту OpenGL. Пока рисуется сцена, никаких обработок событий GUI производить не нужно. Формирование кадра отдельно,обработка событий GUI отдельно.

Сцена может меняться достаточно интенсивно, после каждого изменения формировать кадр расточительно. Поэтому существует метод update() для отложенного рисования.

Если сам процесс формирования кадра занимает 1.6 секунд, то требуется переделка самого процесса отображения. Для 25 тыс. объектов не большой детализации (элементы GUI) приемлемое время не более 20 мс.
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #6 : Июнь 22, 2021, 11:42 »

Например какой нибудь QCad при перемещении 100500 объектов перемещает только общий для всех boundingBox, сами объекты не рисует при перемещении, ну либо ставит в очередь отрисовки ~раз в секунду.
Другие "прореживают" перемещаемые объекты, берут (к примеру) каждый 10-й, ну либо внутри есть хардкод некоего количества легко перемещаемых объектов, вычисляют коэфф. прореживания, согласно этого хардкода.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Июнь 22, 2021, 12:20 »

Если сам процесс формирования кадра занимает 1.6 секунд, то требуется переделка самого процесса отображения. Для 25 тыс. объектов не большой детализации (элементы GUI) приемлемое время не более 20 мс.
25K 3D объектов, пусть половина из них простые. Фейсов 6.5 млн. Не думаю что OpenGL 3.3 потянет за 20 мс.

Просьба "ближе к теме". А то сейчас типа
Цитировать
1.6 сек - ну это медленно! (наверно где-то насвистел) Надо чтобы быстрее - и тогда проблема не возникнет
Это наивный и совсем не инженерный подход Улыбающийся Любые ресурсы конечны и рано или поздно исчерпываются, данная тема о том как рулить в такой ситуации, это тоже нужно и интересно Улыбающийся

.. перемещает только общий для всех boundingBox..
"манипулятор" (общее название драгаемого примитива). Ну и почему "только"? Возможно сцена не так уж велика, и на драге успевает полностью. Логичным выглядит ограничить время рисования, и если оно истекло И (&&) мышь двинулась - выводим то что успели + обязательный манипулятор.

Вот мы и приходим к тому о чем я толкую: а как "прерываться"? На драге - да, годится. А на регулярном обновлении?
« Последнее редактирование: Июнь 22, 2021, 12:44 от Igors » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июнь 22, 2021, 12:43 »

О "побочных" вещах
Если в OpenGL отображать каждый элемент отдельно, то никаких ресурсов не хватит). Важным является отображение всей сцены за минимальное количество обращений к контексту OpenGL.
А как Вы можете это сделать "не отдельно"? У каждого эл-та своя геометрия (вертексы и фейсы) и для каждого придется установить атрибуты и вызвать команду рисования. Возможно Вы имеете ввиду оптимизацию установки шейдеров (типа рисуем сначала все эл-ты с одним материалом и.т.д). Ну тут кое-что оптимизировано, кое-что нет, есть о чем поговорить, но это отнюдь не просто и ускорения "в разы" не обещает.

Пока рисуется сцена, никаких обработок событий GUI производить не нужно. Формирование кадра отдельно,обработка событий GUI отдельно.
Это не одно и то же. "Формирование кадра" не есть "рисование". Формирование никак не связано с OpenGL, сейчас оно производится в главной нитке (с запуском др для того что можно сделать параллельно), и никаких планов это менять к меня нет. А вот замораживать UI ожидая окончания собсно рисования (установка шейдеров и вызовов glDrawElements/Arrays) когда оно уже потеряло актуальность - явно не годится. И опять приходим к тому же: как прерываться?
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #9 : Июнь 22, 2021, 13:34 »

Логичным выглядит ограничить время рисования, и если оно истекло И (&&) мышь двинулась - выводим то что успели + обязательный манипулятор.

Вот мы и приходим к тому о чем я толкую: а как "прерываться"? На драге - да, годится. А на регулярном обновлении?
Тогда будут отрисовываться рандомные первые N объектов, будет выглядеть не очень красиво, у пользователя могут возникнуть вопросы, "а где остальное?"
Здесь лучше 2-й вариант подойдет, с "прореживанием" объектов для отрисовки. При регулярном обновлении делать триггер, по которому прерывать отрисовку
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июнь 22, 2021, 13:50 »

Тогда будут отрисовываться рандомные первые N объектов, будет выглядеть не очень красиво, у пользователя могут возникнуть вопросы, "а где остальное?"
Здесь лучше 2-й вариант подойдет, с "прореживанием" объектов для отрисовки. При регулярном обновлении делать триггер, по которому прерывать отрисовку
Что там "лучше выглядит" (N первых или Nth) - вопрос "второго плана". Важнее как прервать регулярное рисование? Пожуем

- вот мы рисуем (ну вернее посылаем OpenGL команды рисования, строго говоря это еще "запрос") объект за объектом. Что проверять (после каждого)? Нажата клава или мышь? Это можно сделать низкоуровневыми ф-циями, не трогая события. А юзер просто в меню полез. Или открыл окно не имеющее к рисованию отношения. Или еще что. И каждый раз перерисовка заново. А связываться с processEvents на 25K - нереально. И шо ?  Плачущий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июнь 23, 2021, 11:10 »

Ну вот, обсуждение выдохлось - ну да, здесь нет чего-то очевидного, и трудно упрекать что не хотят думать/напрягаться, форум чтобы отдохнуть и потрепаться, это нормально  Улыбающийся Все-таки жаль, тема хороша, "фундаментальна" (не побоюсь этого слова). Ладно, к каким выводам я пришел (подытожу)

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

Правда я попадаю под раздачу: теперь надо в 100 местах проверяться не задействованы ли данные в нитке рисования. Ладно, пошел получать Улыбающийся

Кстати о птичках: не раз слышал что, мол, "рисовать можно/нужно только в paint" - но OpenGL это никогда не волновало, как обманчивы "прописные истины" Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3245


Просмотр профиля
« Ответ #12 : Июнь 24, 2021, 00:35 »

"рисовать можно/нужно только в paint"

вроде уже давно нет
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.053 секунд. Запросов: 23.