首页 > 解决方案 > GtkDrawingArea / cairo 视觉故障

问题描述

我正在创建一个 GTK+ 3 应用程序,它使用 Cairo 在 GtkDrawingArea 小部件中绘制动画。我得到视觉故障,例如在下图中观察到的故障。这些仅针对单个帧出现,每帧可能没有,或一个或多个。我正在寻求帮助以识别可能的问题。以下是我的代码的详细信息:

在我开始gtk_main()循环之前的主要方法中,我连接了一个超时。

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

"window"是我的 GtkWindow 的 id。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)。在这个方法中,我通过懒惰的画家算法绘制了我的 3D 条形图,每个条形图由三个平行四边形组成,并且这些条形图按 z 顺序绘制。

这不是我的计算机无法跟上帧渲染的问题,而是以某种方式破坏了帧缓冲区。我将超时设置为 1000 毫秒以捕获下面的图像。

我没有给gtk_widget_set_double_buffered().

我无法在使用 XMing 作为 X 服务器的 Linux 的 Windows 子系统 (WSL) 上观察到问题,这让我认为这可能是一个库问题,或者是一些定义不明确的行为。

第一张图片是我的程序在正常运行期间出现的视觉故障。在第二个中,我修改了代码并将条形的高度固定为柔和的渐变。这可以更好地了解这个问题,但它仍然非常令人费解。

故障图像 故障图像

开发库包详情:

$ 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

编辑:这是另一个非常有趣的问题截图。

故障图像

标签: animationgtkgtk3cairovisual-glitch

解决方案


拳头,调用gtk_widget_queue_draw主窗口没有意义,因为只GtkDrawingArea需要高频更新。重绘未与之交互的控件会毫无价值地增加开销。

接下来,我在您的 UI 中看不到任何想要不断重绘绘图区域的内容。您应该根据事件重绘:左侧面板中已更改的参数值,或者用户在绘图区域中单击以更改视点(如果您支持的话)。您可能会触发超时以响应控制更改并在更改另一个更改时重新初始化它,以便用户在半秒内更改他们想要的所有设置,然后显示最终结果而不是中间更改。当您的控件的值可以像GtkSpinButton您使用的 s 一样快速变化时,这会很有用。

根据您的测试,如果每秒调用一次绘图代码而不是每 50 毫秒给您一个结果,那么问题很可能出在您的绘图代码中,而不是 GTK+ 绘制它的方式。为了确保是这种情况,您可以禁用重绘的超时源,并添加一个按钮,单击该按钮会触发一次重绘。这样一来,整个频率的事情就不在等式了,你仍然应该有那些渲染错误。

下一步是向我们展示draw信号处理程序中的代码,因为错误可能就在那里。如果要调试它,您可能可以拆分绘图,以便在绘制每个直方图栏后将要绘制的 cairo 表面保存在文件中。然后使用图像编辑器逐个图像查看更改,您将看到问题发生在哪个图像上。通过一些日志记录,您将看到哪些值触发了问题。


推荐阅读