LINUX.ORG.RU

Почему прога на ГТК может пропусакть кадры???


0

0

Вобщем есть сишная ГТК-прога которая по тайм-ауту читает порциями данные из файла и рендерит их на GdkPixmap. после рендерига делается gtk_widget_queue_draw() дабы ети изменения отобразились в окне. Так вот ети изменения иногда пропускаются тоесть картинка держится два тайм-аута вместо одного. а промежуточный кадр непонятно куда девается

★★★★★

Ещё замечено что с увеличением тайм-аута етот еффект исчезает. а при уменьшении - наоборот

cvv ★★★★★
() автор топика

не закончена отрисовка предыдущего кадра к моменту queue_draw или 2 queue_draw в очереди -> срабатывают как один.

lb
()
Ответ на: комментарий от lb

а как с етим боротся??

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

предложение такое: в отдельном треде самостоятельно вызывать gdk_invalidate_*. по идее должно получиться.

lb
()
Ответ на: комментарий от lb

а идею можешь обьяснить???

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

Cтранно - не помогает. 8-(

void
gdk_flush (void)
{
GSList *tmp_list = _gdk_displays;

while (tmp_list)
{
XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
tmp_list = tmp_list->next;
}
}

simply flushes X queue.
nothing to Expose events handling related.

Valeriy_Onuchin ★★
()
Ответ на: Cтранно - не помогает. 8-( от Valeriy_Onuchin

в отдельном треде самостоятельно вызывать gdk_invalidate_*

хорошая идея. Вставь какой-нибудь "refresh timer",
который будет вызывать gdk_window_process_all_updates.
На самом деле мы это пользуем, но под gdk-M$-windows version.

Valeriy_Onuchin ★★
()
Ответ на: Cтранно - не помогает. 8-( от Valeriy_Onuchin

Thanks

А я то думал ...

Жаль что руки до исходников не доходят ;-))

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

не моё это дело, но! trace вызовов дает в общем неплохие результаты.

lb
()

попытаюсь обьяснить ..

1) gtk достаточно умен и отрисовку делает достаточно мудро .. допустим у тебя есть рутина которяа хочет что то нарисовать но не знает как .. она вызывает кучу функций которые что то рисуют ... сама тоже вызывает кучу рисования ... если бы это рисование происходило в момент вызова функции отрисовки то могло бы возникнуть ситуация при которой *один и тот же объект отрисовывался одинаково много раз* - отрисовка достаточно весомая операция и ее хорошо бы соптимизировать - то есть например отрисовывать только последнее состояние объекта принимаемое по окончанию работы рутины .. gtk старается так и делать ..

2) expose eventы *НЕ посылаются X клиентами (окнами)* - expose это прираготива X servera проинформировать клиента что некоторые его *видимые* области требуют перерисовки (не могут быть восстановлены из backing store или других[более быстрых{чем перерисовка}] мест)

-- из 1) понятно что уменьшенее таймаута усиливает эффект пропускания временной отрисовки, а увеличение уменьшает .. (note: сама процедура прорисовки требует время)

lg ★★
()
Ответ на: комментарий от lg

есть еще так называемя компрессия Expose/Paint events,
когда несколько Expose events обьединяются в один a
invalidated regions "суммируются".
это стандратная "техника" применяемая как в
gdk (X11, win32), так и в Qt, win32 GDI ... и у нас.
Вполне возможно, что перед нами именно этот случай,
то о чем намекал lb
"2 queue_draw в очереди -> срабатывают как один."

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

>есть еще так называемя компрессия Expose/Paint events, когда несколько Expose events обьединяются в один

ага - мне приходилось наблядать когда они пару десятков секунд суммировались а потом на екран вываливался последния кадр. В течение суммирования екран был белым хотя все кадры зелёные.

А в общем всё полечили. Ещё раз спасибо

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

> А в общем всё полечили. Ещё раз спасибо

тут уже профессинальный интерес ;-)
дело в том, что эта самaя "компрессия" может быть и
на более высоком уровне (т.е. gtk).
например, у нас, чтобы widget был перерисован,
надо, чтобы он еше об этом попросил об этом ...

посмотрел, что у них творится в gtkmain.c

case GDK_EXPOSE:
if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
{
gdk_window_begin_paint_region (event->any.window, event->expose.region);
gtk_widget_send_expose (event_widget, event);
gdk_window_end_paint (event->any.window);
}
else
gtk_widget_send_expose (event_widget, event);
break;

не, вроде как все делается на gdk_level ...
а вот очень полезный (для тебя ;-) комментарий:

/**
* gtk_widget_send_expose:
* @widget: a #GtkWidget
* @event: a expose #GdkEvent
*
* Very rarely-used function. This function is used to emit
* an expose event signals on a widget. This function is not
* normally used directly. The only time it is used is when
* propagating an expose event to a child %NO_WINDOW widget, and
* that is normally done using gtk_container_propagate_expose().
*
* If you want to force an area of a window to be redrawn,
* use gdk_window_invalidate_rect() or gdk_window_invalidate_region().
* To cause the redraw to be done immediately, follow that call
* with a call to gdk_window_process_updates().
*
* Return value: return from the event signal emission (%TRUE if the event was handled)
**/




Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

>т.е. пользуй gdk_window_process_updates вместо

>gdk_window_process_all_updates - это экономнее

Думаю что здесь я много не секономлю. У меня всего два ГДК-окна - main_window и DrawingArea. из которых я непосредственно юзаю только второе ну и expose-event тоже посылю только второму.

Хотя надо будеть подумать в етом направлении

cvv ★★★★★
() автор топика
Ответ на: комментарий от Valeriy_Onuchin

>т.е. пользуй gdk_window_process_updates вместо >gdk_window_process_all_updates - это экономнее

попробовал использовать gdk_window_process_updates на DrawingArea но ничего хорошего не вышло. Возможно ето надо юзать на main_window.

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

>>т.е. пользуй gdk_window_process_updates вместо

>>gdk_window_process_all_updates - это экономнее

>попробовал использовать gdk_window_process_updates на DrawingArea но ничего хорошего не вышло. Возможно ето надо юзать на main_window.

Попробовал на main_window - резултат тот-же -- ничего хорошего

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

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

А что плохого в том, что кадры теряются? Пользователь все равно это не заметит.

anonymous
()
Ответ на: комментарий от anonymous

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

Кажись твоя правда что в программе кроме всего прочего есть некоторые ошибки.

>А что плохого в том, что кадры теряются? Пользователь все равно это не заметит.

Плохо то что заметит: у меня между кадрами предполагается большая фиксированная пауза и посему выпадание кадра *сильно* заметно на глаз.

результат работы проги больше смахивает на показ слайдов.

Плохо то что время рендеринга большое и кроме того сильно колеблется (от 10 до 300 милисекунд). Следственно если я ставлю фиксированную паузу в 200 мс то начинаются проблемы. (Приведённые проблемы)

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

Да. Ну вопросы такие -

Картинка сильно изменяется каждый раз? Может, ее по частям перерисовывать?

Сама картинка долго рисуется или данные долго считаются?

Почему таймаут в 200 критичен? Все-таки для глаз это очень большой таймаут. Если человек на картинку постоянно смотрит, ему лучше побыстрее менять.

Можно ли данные с задержкой выводить - отрисовавать на нескольких GdkPixmap'ах и по мере поступления отрисованных картинок отображать.

anonymous
()
Ответ на: комментарий от cvv

> время рендеринга большое и кроме того сильно колеблется (от 10 до 300 милисекунд).

Ну и делай expose после готовности кадра. Только вот если структура программы похожа на это:

while( running ) if ( render() ) expose();

то иммет смысл сделать так: while( running ) if ( render() ) sem_post( exposer );

а в отдельном треде так: while( running ) { sem_wait( exposer ); expose(); }

Основной смысл в следующем -- если рендеринг жрет процессор, то есть вероятность того что бедной процедуре отрисовки gdk просто не хватает времени.

момент 2: при ~10мс шедулере (ядра <2.5), рендеринг 10мс кадров мало кому оставит время для действий. здесь имеет смысл дать треду expose приоритет повыше.

lb
()
Ответ на: комментарий от lb

хотелось бы отметить еще один аспект этой проблемы.

"timer events" обычно отрабатываются в "main event loop"
там же, где и "gui events". обычно (qt, fox-toolkit, у нас, etc)
"event loop" устроена так, что разные события (timer events,
gui input, gui expose events, fd/sockets polling etc)
отрабатываются с разными приоритетами.
Обычно приоритет у "expose events" самый низкий -
это позволяет "painting as background job".
Этим можно обяснить пропуски отрисовки.
Обычно всегда есть методы форсирования отработки
"some specific event type", как gdk_window_process_all_updates,
или отработки всех "pending events".

... ладно - это уже теория ;-)

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

> Обычно приоритет у "expose events" самый низкий

поправка: один из самых низких

Valeriy_Onuchin ★★
()
Ответ на: комментарий от anonymous

>Да. Ну вопросы такие -

>Картинка сильно изменяется каждый раз? Может, ее по частям перерисовывать?

Я над етим уже думал. в очередной версии так и сделаю. По мере погружения в ГДК/ГТК

>Сама картинка долго рисуется или данные долго считаются?

картинка долго рисуется.

>Почему таймаут в 200 критичен? Все-таки для глаз это очень большой таймаут. Если человек на картинку постоянно смотрит, ему лучше побыстрее менять.

В конечном итоге должно получится чтото-похожее на слайд-шоу. Пропускать слайды нельзя.

>Можно ли данные с задержкой выводить - отрисовавать на нескольких GdkPixmap'ах и по мере поступления отрисованных картинок отображать.

cvv ★★★★★
() автор топика
Ответ на: комментарий от lb

>> время рендеринга большое и кроме того сильно колеблется (от 10 до 300 милисекунд).

>Ну и делай expose после готовности кадра.

Ну я так и делаю.

>Только вот если структура программы похожа на это:

>while( running ) if ( render() ) expose();

>то иммет смысл сделать так: while( running ) if ( render() ) sem_post( exposer );

>а в отдельном треде так: while( running ) { sem_wait( exposer ); expose(); }

>Основной смысл в следующем -- если рендеринг жрет процессор, то есть вероятность того что бедной процедуре отрисовки gdk просто не хватает времени.

>момент 2: при ~10мс шедулере (ядра <2.5), рендеринг 10мс кадров мало кому оставит время для действий. здесь имеет смысл дать треду expose приоритет повыше.

На текущий момент прога однотредовая а делать её много-тредовой не вижу ни какого смысла так как кроме увеличения сукся в 10 раз я от тредов больше ничего не жду

cvv ★★★★★
() автор топика
Ответ на: комментарий от Valeriy_Onuchin

Вобщем большое спасибо за gdk_window_process_all_updates()

а там по мере необходимости будем выполнять оптимизацию алгоритма рендеринга.

cvv ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.