GtkDrawingArea / Каир визуальные глюки - PullRequest
2 голосов
/ 04 июля 2019

Я создаю приложение GTK + 3, которое рисует анимацию с использованием Cairo в виджете GtkDrawingArea. Я получаю визуальные глюки, такие как наблюдаемые на изображениях ниже. Они появляются только для одного кадра, их может не быть, или один, или более одного на кадр. Прошу помощи в выявлении возможной проблемы. Вот детали моего кода:

В моем основном методе перед запуском цикла gtk_main() я подключаю время ожидания.

g_timeout_add(50, queue_draw, gtk_builder_get_object(builder, "window")); 

"window" - это идентификатор моего GtkWindow. Функция queue_draw выглядит следующим образом:

gboolean queue_draw(gpointer user_data)
{
  gtk_widget_queue_draw(GTK_WIDGET(user_data));
  return TRUE;
}

Я бы подумал, что мог бы передать объект GtkDrawingArea этой функции, а не всему моему GtkWindow, но в этом случае анимация исчезает. Мне также интересны комментарии по поводу такого поведения, но это не мой главный вопрос.

Сигнал отрисовки моего GtkDrawingArea подключен к функции gboolean drawing_area_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data). Внутри этого метода я рисую свою трехмерную гистограмму по алгоритму ленивого художника, каждый столбец состоит из трех параллелограммов, а столбцы рисуются в z-порядке.

Это не проблема, если мой компьютер не успевает за рендерингом кадров, что-то портит буфер кадров. Я установил тайм-аут на 1000 мс, чтобы сделать снимки ниже.

Я не звонил на gtk_widget_set_double_buffered().

Мне не удалось наблюдать проблему в подсистеме Windows для Linux (WSL) с использованием XMing в качестве X-сервера, что заставляет меня думать, что это может быть проблема библиотеки или какое-то плохо определенное поведение.

Первое изображение имеет визуальный сбой во время моей программы в нормальной работе. Во втором я изменил код и установил высоту столбцов с плавным градиентом. Это дает намного лучшее представление о проблеме, но все же очень озадачивает.

image of glitch image of glitch

Детали пакета библиотеки разработки:

$ dpkg --list | egrep 'lib(cairo|gtk).*-dev'
ii  libcairo2-dev:amd64                                1.15.10-2ubuntu0.1                           amd64        Development files for the Cairo 2D graphics library
ii  libgtk-3-dev:amd64                                 3.22.30-1ubuntu3                             amd64        development files for the GTK+ library

подробности метаинформации библиотеки:

$ pkg-config --modversion gtk+-3.0 glib-2.0 gdk-pixbuf-2.0 cairo
3.22.30
2.58.1
2.36.11
1.15.10

x11 детали:

$ xdpyinfo | head -n 5
name of display:    :0
version number:    11.0
vendor string:    The X.Org Foundation
vendor release number:    12001000
X.Org version: 1.20.1

Детали Linux (на самом деле Zorin OS 15, а не Ubuntu 18.04):

$ uname -a
Linux <hostname> 4.18.0-25-generic #26~18.04.1-Ubuntu SMP Thu Jun 27 07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

edit: Вот еще один очень интересный скриншот проблемы.

image of glitch

1 Ответ

3 голосов
/ 04 июля 2019

Fist, вызов gtk_widget_queue_draw в главном окне не имеет смысла, так как только GtkDrawingArea необходимо обновлять с высокой частотой. Перерисовка элементов управления, с которыми вы не взаимодействовали, добавляет издержки без значения.

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

Из вашего тестирования, если вызов кода рисования каждую секунду вместо каждых 50 мс дает вам этот результат, то, скорее всего, проблема заключается в вашем коде рисования, а не в том, как его рисует GTK +. Чтобы убедиться, что это так, вы можете отключить источник перерисовки, который перерисовывается, и добавить кнопку, при нажатии которой запускается одна перерисовка. Таким образом, вся частотная составляющая выходит за рамки уравнения, и у вас все равно должны быть ошибки рендеринга.

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

...