2
votes

I am creating a GTK+ 3 application which draws an animation using Cairo in a GtkDrawingArea widget. I get visual glitches, such as the ones observed in the images below. These appear only for a single frame, there may be none, or one, or more than one per frame. I am asking for help in identifying the possible issue. Here are the details of my code:

In my main method before starting the gtk_main() loop I hook up a timeout.

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

"window" is the id of my GtkWindow. The queue_draw function is as follows:

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

I would think that I could pass the GtkDrawingArea object to this function rather than my whole GtkWindow, but the animation disappears in that case. I am also interested comments on this behavior but it is not my main question.

The draw signal of my GtkDrawingArea is hooked to a function gboolean drawing_area_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data). Inside this method I draw my 3D bar chart by a lazy painter's algorithm, each bar being made of three parallelograms, and the bars being drawn in z order.

It is not a problem with my computer failing to keep up with the frame rendering, somehow corrupting a frame buffer. I set the timeout to 1000ms to capture the images below.

I have not made any calls to gtk_widget_set_double_buffered().

I was not able to observe the issue on Windows Subsystem for Linux (WSL) using XMing as the X server, which makes me think it might be a library issue, or some poorly defined behavior.

The first image is of the visual glitch during my program in normal operation. In the second, I modified the code and fixed the height of the bars to a gentle gradient. This gives a much better view of the issue, but it still very puzzling.

image of glitch image of glitch

development library package details:

$ 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

library metainformation details:

$ 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 details:

$ 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 details (actually Zorin OS 15 not 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: Here is another very interesting screenshot of the issue.

image of glitch

1

1 Answers

3
votes

Fist, calling gtk_widget_queue_draw on the main window makes no sense as only the GtkDrawingArea need to be updated at a high frequency. Redrawing controls you didn't interact with adds overhead for no value.

Next, I see nothing in your UI that wants to have the drawing area redrawn constantly. You should redraw in reaction to events: a parameter value that has changed in your left panel, or the user clicking in the drawing area to change the viewpoint (if that's something you support). You may event fire up a timeout in reaction to control changes and reinitialize that when another one is changed, so that it lets half a second to the user to change all the settings they want and then display the final result instead of the intermediate changes. This can be useful when you have controls with a value that can change fast like the GtkSpinButtons you use.

From your testing, if calling the drawing code every second instead of every 50ms gives you that result, then the problem is most probably in your drawing code, not on the way GTK+ draws it. To make sure that's the case, you can disable the timeout source that redraws, and add a button that when clicked triggers a single redraw. This way the whole frequency thing is out of the equation, and you should still have those rendering bugs.

The next step is to show us the code in the draw signal handler, as the bug probably lays there. If you want to debug it, you probably can split the drawing so that you save the cairo surface you're drawing to in a file after each histogram bar is painted. Then seeing the changes image by image with an image editor, you will see on which image the problem happens. With some logging, you will see which values trigger the problem.