JUCE Painting Performance Still Needs Improvement

Hello everyone,

I’m aware that this is a common issue, but I need to address it once more. :slight_smile:

I’ve profiled my app and optimized it to the best of my ability. Currently, everything is running incredibly fast, except for the rendering process when there’s animation involved (such as the spectrum analyzer and meters). This animation is causing a significant strain on the CPU.

I’ve tried various approaches to improve the situation, including reducing the rendering area, using solid colors instead of gradients, simplifying all my juce::Path objects, and even implementing specific compiler flags provided by JUCE. While these efforts have made my app faster, it’s still placing a heavy load on the CPU, sometimes consuming up to 95% of the entire process.

It would be fantastic if we could achieve smooth animations without causing the fans to start whirring loudly.

I’ve noticed that FabFilter plugins can handle a much larger number of rendering commands simultaneously. You can try using Pro-Q and see how smoothly you can manipulate all 24 filters, which involves a considerable amount of rendering.

I would like to suggest that the JUCE team prioritize addressing this bottleneck. Specifically, it would be great if we could achieve 60 FPS rendering for a few paths without a significant CPU overhead.

Furthermore, it would be fantastic to have the ability to achieve smooth animations without any drop in FPS. Even the tiniest animation currently causes stuttering.

I haven’t explored OpenGL as it’s considered a deprecated technology now.

I kindly request the JUCE team to prioritize addressing this issue first. :slight_smile:

Please bump if you’ve read and agree with this.


What you could probably try is running a side thread for the part that builds the path and turns into an image, and then paint() only paints the already-rendered image.

That made a huge impact for me.

I have an example for that here:

1 Like

I strongly suspect this is achieved with hardware accelerated rendering such as OpenGL, Metal, Vulkan, etc.

What platform(s) are you running / testing on?

For macOS I’m not sure there is a whole lot of room for improvement, on Windows improvements are being worked on in the form of using a Direct2D renderer (see here for more details).

BTW, this is also a huge issue for us. Apparently since JUCE switched to the VBlankAttachment for it’s paint synchronization, all other plugins using OpenGL are now throttled to the point that they become unusable.

We’ve had multiple customers and our sound-designers complain that opening one instance of the NEXUS UI throttles the whole DAW if a FabFilter product also has its UI open.

Closing either UI fixes the issue. So they are interfering with each other. This wasn’t an issue until the VBlankAttachment stuff, so we suspect that waiting for the VBlank in that high-priority thread is somehow preventing the other UI from waiting for its VBlank and thus massively burning CPU.


:sob: OK I’ll raise this with the team.


Isn’t it surprising?

Component repainting always involves using or blocking the message thread (regardless if software/core-graphics/juce-openGL renderer) .
Especially when the message-thread is shared with the host and other plugins, this can be problematic.

Path-filling always uses the EdgeTable/scan-line processor on CPU - not very performant for waveforms.

What can be done:

  • make the drawing itself faster
  • intelligent VBlankAttachment, which reduces fps programmatically, If too large a proportion of the message thread time is used
  • advanced solution: decouple the drawing from the message thread (for example via native openGL in renderOpenGL() callback, without blocking the message thread)

But there is some good news:

More and more hosts use separate processes and thus separate message threads. So the problem should solve itself over time.


By the way, I was referring to both the Windows and macOS (arm) platforms. I’m genuinely pleased to see that progress is being made with Direct2D, and it’s already delivering noticeable improvements, from what I can see.

@reFX what platform(s) are you experiencing this on?

I just tried modifying a simple plugin to draw an animated line that moves from one side of the editor window to the other, using VBlankAttachment to sync the animation with the screen refresh. With an instance of that plugin loaded and visible alongside FabFilter Pro Q 2/3 in Reaper 6.82, I don’t see any drawing stalls in the FabFilter plugin, on Windows 10/11 or macOS 14 Arm.

I think we’re going to need an example of a plugin that triggers this problem, or at least a thorough description of how the drawing and environment is set up. As well as specifying the affected OS, it would be helpful if you could let us know which host applications, target architectures, and plugin formats are affected.

1 Like

@anthony-nicholls @reuk I can not reproduce it, but the sound designer who brought it to my attention can. He didn’t provide exact version numbers, but he will do so once he’s back in the studio (after this weekend).

What he told me so far is embarrassing, and I deeply regret even mentioning it, but technically JUCE still supports it, so here it goes:

  • Windows 7 (latest version available)
  • Cubase 5 (seriously), but he also tried Cubase 10 and say it’s slightly better there, but still very noticeable
  • FabFilter Pro Q from around a year ago

Once he’s back in the studio, he also promised to check again with a more modern system (Windows 11 and Cubase 12). I will also suggest driver updates to him, etc.

I can send you guys (all of you) a free copy of NEXUS4 to test with. We don’t do anything related to VBlankAttachment in there. Just a regular Timer (at 60 Hz), and from that timerCallback, we update several visualizations (UV meters, scopes, keyboard state, etc.), which usually is a few fast calculations and a call to repaint for only those visualizations whose state changed enough to be noticeable.

Since this is all on Windows, all drawing is done on the CPU. The FabFilter plugins probably use OpenGL.


With Windows 11 and Cubase 12, he can not reproduce the issue. We can only assume that the customers who complained had similar outdated setups. We don’t even support Windows 7 anymore. We haven’t for years.

I’m sorry for wasting everybody’s time. In the future, I will ensure I have all the necessary data before reporting any problems.