On the efficiency of drawDashedLine

gui

#1

While working on a piano roll application, I noticed that dashed line drawing is making repaints very slow, confirmed on both Linux and Windows, software/OpenGL renderer.

To give a bit more context, the application draws a bunch of vertical dashed lines at a fixed interval to mark every 1/8 of a beat; and when maximized the window holds about up to 300 such dashed lines. Scrolling becomes noticeably slow when it goes above somewhere around 100 lines.

Using drawLine instead of drawDashedLine significantly improves the performance, though that’s not precisely the kind of effect I want. So I spent a bit of time digging into the JUCE codes and found that drawDashLine actually breaks each dashed line down into some a hundred mini drawLines.

I wonder if there’s any smarter/faster way to draw dashed lines?


#2

If you’re drawing vertical or horizontal lines, then the absolute fastest way would be to build a list of rectangles and use Graphics::fillRectList()


#3

Thank you Jules. I tried replacing drawDashedLine with a list of width-1 rectangles, but it ended up being even slower.

Here’s what I’m doing,

  RectangleList<float> dashes;
  // Blick is an internal integer unit defined as 1/705,600,000 of a beat.
  for(Blick b = firstBlick; b <= lastBlick; b += blickRounding) {
    int x = coordinator.getXFromBlick(b);
    for(int i = 0; i < height / pxPerSemitone; i ++) {
      dashes.add(x, yOffset + i * pxPerSemitone, 1, dashHeight);
    }
    // const float dashLength[2] =
    //   {dashHeight, pxPerSemitone - dashHeight};
    // g.drawDashedLine(Line<float>(x, yOffset, x, height), dashLength, 2);
  }
  g.fillRectList(dashes);

#4

I just discovered that breaking down the dashed line into a bunch of drawVerticalLine calls (instead of the more flexible drawLine) makes the repaint a lot faster - like literally replacing dashes.add(...) with drawVerticalLine.

However internally drawVerticalLine is implemented by fillRect, which supposedly runs slower than fillRectList for some large enough quantity (and in my case the number of dashes is on the order of thousands). What went wrong?


#5

Are you sure the drawing is slow, and not building the RectangleList? Calling RectangleList::add won’t scale very well, you’d be better calling addWithoutMerging. You might also want to cache the list rather than create it each time you paint


#6

Thanks again! You’re right on the spot. After switching to addWithoutMerging it now runs blazingly fast :smile:


#7

The moral of this story is always use a profiler before making assumptions about performance!