Animation GtkDrawingArea/cairo视觉故障

Animation GtkDrawingArea/cairo视觉故障,animation,gtk,gtk3,cairo,visual-glitch,Animation,Gtk,Gtk3,Cairo,Visual Glitch,我正在创建一个GTK+3应用程序,它在GtkDrawingArea小部件中使用Cairo绘制动画。我会出现视觉上的小故障,如下图中观察到的。这些仅针对单个帧显示,每个帧可能没有、一个或多个。我请求帮助确定可能的问题。以下是我的代码的详细信息: 在我的main方法中,在启动gtk_main()循环之前,我连接了一个超时 g_timeout_add(50, queue_draw, gtk_builder_get_object(builder, "window")); “窗口”是我的GtkWind

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

在我的main方法中,在启动
gtk_main()
循环之前,我连接了一个超时

g_timeout_add(50, queue_draw, gtk_builder_get_object(builder, "window")); 
“窗口”
是我的GtkWindow的id。
queue\u draw
功能如下:

gboolean queue_draw(gpointer user_data)
{
  gtk_widget_queue_draw(GTK_WIDGET(user_data));
  return TRUE;
}
我认为我可以将GtkDrawingArea对象传递给这个函数,而不是我的整个GtkWindow,但在这种情况下动画消失了。我也对这种行为感兴趣,但这不是我的主要问题

我的GtkDrawingArea的绘图信号连接到一个函数
gboolean drawing\u area\u draw(GtkWidget*小部件、cairo\u t*cr、gpointer user\u数据)
。在这个方法中,我用一个懒惰的画家的算法绘制了我的3D条形图,每个条形图由三个平行四边形组成,并且这些条形图是按z顺序绘制的

这不是我的计算机无法跟上帧渲染的问题,因为它会损坏帧缓冲区。我将超时设置为1000ms以捕获下面的图像

我没有调用任何
gtk\u widget\u set\u double\u buffered()

我无法在使用XMing作为X服务器的Windows Linux子系统(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 4.18.0-25-generic#26~18.04.1-Ubuntu SMP周四6月27日07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
编辑:这里是这个问题的另一个非常有趣的截图


首先,在主窗口上调用
gtk\u widget\u queue\u draw
没有任何意义,因为只有
gtkdrawingara
需要高频更新。重新绘制未与之交互的控件会增加开销,但没有任何价值

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

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


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

我同意,重新绘制整个GtkWindow是没有意义的。但是,如果我为GtkDrawingArea排队重新绘制,我的图形就会消失。我理解绘画通常是事件驱动的,但请记住这是一个动画。我定期对绘图进行排队,以便为我的图形设置动画。欢迎提出建议。由于硬编码条的高度,代码每次都会发出完全相同的Cairo调用序列,但这些小故障有时仅在一帧内随机出现。在重新绘制GtkDrawingArea时,图形不应消失。它应该只安排一个回调调用,处理来自事件循环的
draw
信号,从而绘制场景。如果您的硬编码值触发了错误,那么正如我所说的,将中间图像保存到一个文件中,并确保出现故障的是绘图管道,而不是显示管道。尚未进行该实验,但我尝试在绘图区域上设置gtk_widget_set_double_buffered FALSE,现在这种行为非常奇怪。如果在窗口上对绘图进行排队,则会出现正常的故障行为。如果在绘图区域上对绘图进行排队,则会出现故障行为,但有两个绘图相互重叠,并且水平偏移一点。我怀疑这个小故障可能是由于在不同的线程上并发调用了两次draw处理程序。但为什么会这样呢?为什么它会被抵消?所有这些都没有多大意义。此外,当我调整窗口大小时,背景中的偏移图会消失,并在我停止调整大小后再次出现,但不管怎样,这些小故障仍会继续。也许这是两个不同的问题。你在使用线程吗?GTK使用事件循环,因此除非您正在创建自己的线程,否则不能中断绘图。
$ 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