OberonCore
https://forum.oberoncore.ru/

И снова о мерцании.
https://forum.oberoncore.ru/viewtopic.php?f=24&t=3333
Страница 1 из 2

Автор:  Иван Кузьмицкий [ Среда, 16 Март, 2011 13:19 ]
Заголовок сообщения:  И снова о мерцании.

Очень часто наблюдаем такую картину:

На форме располагаются несколько отображений-контейнеров с вложенными текстами (и различными контролами, как стандартными, так и нет). При вводе текста в один контейнер необходимо автоматически подогнать размер этого текст-вью под заданный размер. Подгонка делается банальным изменением контекста текствью при обработке сообщения EditMsg.

Так вот, эта самая подгонка приводит к заметным мерцаниям остальных контейнеров.

Если захватить изображение с экрана (я использую программу CamStudio, которая захватывает кадры с дискретностью 5 мсек), то при просмотре записи видно, как контейнер стирает своё изображение, оставляя серый фон. Так длится примерно 0.5 - 0.7 секунды, после чего контейнер перерисовывает себя заново.

Вот эта вот задержка и заметна глазу. Но не объяснима :(

Автор:  Иван Кузьмицкий [ Среда, 16 Март, 2011 14:12 ]
Заголовок сообщения:  Re: И снова о мерцании.

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

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

Но сама картина флика (стирание - пауза (визуально ощутимая) - перерисовка) остаётся прежней.

Автор:  Илья Ермаков [ Среда, 16 Март, 2011 18:11 ]
Заголовок сообщения:  Re: И снова о мерцании.

Видимо, так какое-то действие вынесено на Action, нет?

Автор:  Иван Кузьмицкий [ Среда, 16 Март, 2011 19:51 ]
Заголовок сообщения:  Re: И снова о мерцании.

Action стоит вне последовательности "RemoveFrames - RestoreRoot"... А я наблюдаю ситуацию "затирание - визуальная пауза - отрисовка".

Автор:  Пётр Кушнир [ Среда, 16 Март, 2011 20:14 ]
Заголовок сообщения:  Re: И снова о мерцании.

В сложных отображениях внутри процедуры Restore может вызываться Views.InstallFrame, которая, в свою очередь инициирует отсылку сообщения, UpdateCaches только что внедрённому, а если внедрённое отображение тоже сложное, то обработка каскада таких сообщений может внести задержку.
Хотя, опять же неясно, если во время перерисовки мы находимся всё время внутри процедуры RestoreRoot то откуда берётся период визуальной паузы после затирания, ведь никаких средств для продолжения обработки сообщений виндовс не производится.

Автор:  Иван Кузьмицкий [ Среда, 16 Март, 2011 21:28 ]
Заголовок сообщения:  Re: И снова о мерцании.

Вырезал три кадра из видео. Первый кадр - непосредственно перед затиранием, второй - визуальная пауза, а третий - уже произошла перерисовка. На линейке времени видна продолжительность паузы - 0.6сек.

Вложения:
Комментарий к файлу: Клик по закладке непосредственно перед затиранием
flicks-1.png
flicks-1.png [ 162.43 КБ | Просмотров: 16157 ]
Комментарий к файлу: Пауза 0.6 сек.
flicks-2.png
flicks-2.png [ 152.64 КБ | Просмотров: 16157 ]
Комментарий к файлу: После паузы сразу же мгновенная отрисовка
flicks-3.png
flicks-3.png [ 161.86 КБ | Просмотров: 16156 ]

Автор:  Илья Ермаков [ Среда, 16 Март, 2011 23:16 ]
Заголовок сообщения:  Re: И снова о мерцании.

Попробуйте пологироваться из главного цикла HostMenus.Loop? Сколько там тактов проходит между этими моментами?

Автор:  Сергей Губанов [ Четверг, 17 Март, 2011 00:06 ]
Заголовок сообщения:  Re: И снова о мерцании.

Так у Вас же переключение между страницами Tab-View. Это может виндос глючить, а не Блэкбокс. Помню я однажды ещё в Дельфях нагородил мильён контролов в Tab-View и винда очень медленно перерисовывала переключение между его страницами.

Автор:  Илья Ермаков [ Четверг, 17 Март, 2011 00:09 ]
Заголовок сообщения:  Re: И снова о мерцании.

Не, у товарищей ярославцев уже свои табы :)

Автор:  Иван Кузьмицкий [ Четверг, 17 Март, 2011 00:53 ]
Заголовок сообщения:  Re: И снова о мерцании.

Посчитал количество итераций главного цикла, вот каким образом.

1) Завёл экспортированную переменную HostMenus.loopCount.
2) В цикле HostMenus.Loop инкрементирую INC(loopCount).
3) На форму визарда (где наблюдались паузы) вывел Edit Field и связал его с интерактором HostMenus.loopCount.
4) Запустил периодическое действие, которое выполняет Dialog.UpdateLInt(HostMenus.loopCount).
5) Заснял поведение формы визарда.

Результаты.

1) Фликов стало заметно меньше.
2) Счётчик показывает длительность визуальной паузы (описанной ранее) в размере 8-9 итераций. В основном, 9.
3) На видео не удалось поймать изменения счётчика в течение паузы. Значение счётчика меняется скачком по окончанию паузы в кадре, где происходит отрисовка.

Примерно так.

Автор:  Илья Ермаков [ Четверг, 17 Март, 2011 01:11 ]
Заголовок сообщения:  Re: И снова о мерцании.

Не, с edit не пойдёт, Вы наблюдаете этот счётчик через гуёвые же штуки. А надо попечатать в лог чисто Services.Ticks() и посмотреть.

А 8-9 итераций как раз и даёт 0.6 с, ведь оконный цикл в винде получает управление от ОС с периодом где-то в 50мс.

Автор:  Иван Кузьмицкий [ Четверг, 17 Март, 2011 01:14 ]
Заголовок сообщения:  Re: И снова о мерцании.

Так ведь не сопоставить же содержимое лога с тем, что на видео. А в журнал нет смысла выводить, тот же гуй и получится.

Автор:  Илья Ермаков [ Четверг, 17 Март, 2011 01:24 ]
Заголовок сообщения:  Re: И снова о мерцании.

Ну, в принципе и так ясно, что между моментами отрисовки проходит много оборотов оконного цикла... Теперь бы выяснить, откуда такой протормоз. Всё-таки что-то там в каркасе отложенно происходит... Пологировать, какие Action-ы выполняет Services за этот период?

Автор:  Иван Кузьмицкий [ Четверг, 17 Март, 2011 12:19 ]
Заголовок сообщения:  Re: И снова о мерцании.

Я хочу понять вот что.

Как понимаю, общий принцип отрисовки отражён в процедуре Views.ValidateRoot:

1. Удаляются ненужные фреймы (вызов RemoveFrames).
2. Дерево фреймов перестраивается (вызов RestoreRoot).
2.1. Внутри RestoreRoot вызывается рекурсивная процедура RestoreFrame, которая обходит дерево фреймов и для каждого привязанного к фрейму отображения вызывает метод v.Restore.

На кадрах из видео мы видим, как возникает эффект флика: совершенно нормально отрисовывается контейнер (форма), а внедрённый в него виджет отрисовывается не сразу.

Получается, что сам контейнер как бы не даёт отрисовать внедрёнку? Не могу пока сформулировать точнее, сумбур в мыслях.

Автор:  Иван Кузьмицкий [ Четверг, 17 Март, 2011 13:15 ]
Заголовок сообщения:  Re: И снова о мерцании.

Обнаружил забавную штуку.

В методе Restore формы посчитал количество вызовов InstallFrame и заснял видео на визарде.

Так вот, как только переключаю на закладку с 17 элементами (страничка Контакты), то в лог тут же попадает именно 17 вызовов InstallFrame. Но дальше форма пустая - держится пауза!

И по окончании паузы, форма перерисовывается ещё раз, выводя опять же 17 вызовов InstallFrame.

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

Примечание: в лог выводятся ширина и высота формы (для идентификации в кадре) и подсчитанное количество вызовов InstallFrame.

Вложения:
Комментарий к файлу: Клик по закладке, начало паузы, а форма уже инсталлировала 17 внедрёнок.
form1.png
form1.png [ 66.9 КБ | Просмотров: 16063 ]
Комментарий к файлу: Форма перерисовалась
form2.png
form2.png [ 79.42 КБ | Просмотров: 16063 ]

Автор:  Илья Ермаков [ Четверг, 17 Март, 2011 14:45 ]
Заголовок сообщения:  Re: И снова о мерцании.

Может, затирается чем-то? В FormView.Restore есть ещё MarkRect после InstallFrames, может, оно трёт? Закомментируйте и проверьте?

Автор:  Иван Кузьмицкий [ Четверг, 17 Март, 2011 17:13 ]
Заголовок сообщения:  Re: И снова о мерцании.

Проверил, MarkRect не затирает.

У меня возникло подозрение, что только что инсталлированные на форму вьюхи не рисуются сразу же только потому, что их фреймы ещё не попали в общее дерево. А когда на следующем цикле происходит вызов RestoreRoot, эти фреймы уже лежат на пути обхода RestoreFrame, которая и дёргает за v.Restore.

Ведь внедрение вьюх на форму происходит только в FormViews.View.Restore(). Выходит, что отрисовка самих внедрёнок делается на следующей итерации.

P.S. Хотя, я, наверное, не прав. Вот кусочек из RestoreFrame:

Код:
v.Restore(f, l, t, r, b);
            g := f.down;
            WHILE g # NIL DO   (* loop over all subframes to handle overlaps *)
               dx := f.gx - g.gx; dy := f.gy - g.gy;
               RestoreFrame(g, l + dx, t + dy, r + dx, b + dy);
               g := g.next
            END;


То есть, сперва вызывается Restore, а затем на крайний вьюхин фрейм напускается рекурсивно RestoreFrame.

Автор:  Иван Кузьмицкий [ Пятница, 18 Март, 2011 20:22 ]
Заголовок сообщения:  Re: И снова о мерцании.

Провёл ещё один эксперимент, используя логирование в память (накопленные данные переписываются в журнал позже).

Бросил на форму свою вьюху, которая в методе Restore делает запись в лог. Зафиксировал в логе моменты:
- когда форма инсталлирует эту самую вьюху,
- когда в процедуре Views.RestoreFrames обходятся все инсталлированные на форму фреймы
- когда вызывается метод Restore моей вьюхи.

Заснял на видео, где чётко видно, что во время визуальной паузы метод Restore моей вьюхи вызывается два раза. А самой вьюхи не видно, она не рисуется.

Я-то думал, что каркас каким-то образом откладывает обработку фрейма инсталлированного отображения. Ан нет, всё чётко - инсталлировали, перебрали, вызвали Restore.

Остаётся только WinApi. Тут я пас. То, что происходит между вызовами WinApi.SaveDC и WinApi.RestoreDC, выводится в видимые пиксели с приличной, ощутимой глазу задержкой. А почему - не знаю.

P.S. Хе-хе, для таких исследований пошаговый отладчик - самое то :)

Автор:  Valery Solovey [ Пятница, 18 Март, 2011 22:16 ]
Заголовок сообщения:  Re: И снова о мерцании.

Кстати, да. Недавно в другом месте тоже таоке мнение слышал: для написания программы отладчик не использую, нужен только чтобы разобраться с каким-нибудь чужим кодом.

Автор:  Иван Кузьмицкий [ Пятница, 18 Март, 2011 23:14 ]
Заголовок сообщения:  Re: И снова о мерцании.

Вот ещё что никак не уложится в голове.

Отрисовка формы делается в процессе рекурсивного обхода RestoreFrame, как и все остальные фреймы.

Мерцание хорошо заметно на форме, и ещё лучше видно, когда форма в режиме разметки - с сеточкой.

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

А буфер-то закрывается только один раз, в RestoreRoot, сразу по окончании обхода RestoreRoot. Каким образом сеточка успевает нарисоваться раньше остальных фреймов?

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/