Component painted in two halves, glitchy

I setup a BubbleComponent that moves along with a slider thumb and saw some glitchyness in the painting of the bubble. I then rolled my own tooltip and I’m seeing the same issue, at least on MacOS:

tooltip jank

The component is split in half, horizontally, right where two other components underneath it meet. The top half and the bottom half of the tooltip are painted separately, out of sync.

A lot of glitchiness goes away if I reduce other painting happening at the same time, so I’m assuming this is at least partly a frame rate issue. However, it is still painting in halves and I’d like to understand if this is normal or strange. At first the tooltip was a sibling of what it was painting over, but it doesn’t seem to matter where it is in the hierarchy…

I’ve been trying to reproduce this “split at component boundaries” thing in a fresh project, but no luck, even when I add 20ms sleeps added to paint calls… Maybe someone has an idea or I’m missing something obvious?..

2 Likes

Lol I had this once before I literally modified my design cause I couldn’t figure it out

Do you remember if your tooltip component was a Slider::Listener and if you were calling setBounds on sliderValueChanged?

Things seem less janky if I call repaint on my tooltip from the parent container. But I feel like I must be missing something fundamental. It feels pretty surprising that this component is painted in two different “frames”.

From what I remember it had to do with a transparent child component painting over two other children at once, and for some reason the 3rd child between & optop of the other two was repainting only a partial section of itself while something beneath it was painting.

1 Like

Things I tried that didn’t help:

  • Release mode (just sayin’)
  • Playing with JUCE_ENABLE_REPAINT_DEBUGGING — useful to confirm at a very basic level what is being painted, but pretty hectic and not usable for determining “timing”.
  • Adding a timer and repainting while the tooltip should be active at 60Hz (tearing happens less often, but still problematic)
  • Making the tooltip a child of the editor
  • Avoiding “setBounds” (making the “tooltip” bounds be full editor width/height and using fillRect)
  • Disabling JUCE_COREGRAPHICS_DRAW_ASYNC

How I solved the problem:

  • Getting clear about what exactly is painting when.

I tried logging paint calls, but this gets noisy quickly and it’s hard to determine signal from noise while triggering things in the UI.

I want to look into building out a painting logger (from what I can tell there’s no callbacks/hooks in the painting code), but in the meantime I’ve been doing some performance visualizing with chrome://tracing (now perfetto) so I used that to give me a timeline of when things repaint:

So, it turns out that bottom half of the tooltip was being rendered first, when the slider repainted, and the top half would wait until all the siblings were being repainted, which would happen later.

I fixed the tearing/glitchiness by making sure all the siblings and the tooltip were painted together, basically calling tooltip.repaint() once in the container (not even calling it from sliderValueChanged in the tooltip).

What I don’t know is why the tooltip is even painting in two sections to begin with. Correct me if I’m wrong, but my takeaway is “anytime a component is moving and painting on top of other components, manually tell the underlying components to repaint to avoid tearing/timing issues.” My (incorrect) assumption was that this was automatically handled by JUCE…

4 Likes