We’ve pushed some updates for Images that should help performance when working with D2D images. You can now call Image::setBackupEnabled (false) to disable flushing of the image to main memory after modifying it on the GPU, e.g. via a Graphics instance.
The relevant change is here:
As part of this change, we’ve updated StandardCachedComponentImage, DropShadowEffect, and GlowEffect to use this new behaviour, so projects that are using setBufferedToImage and/or component effects should see performance improvements without needing to make any changes.
Note that disabling image backup has some potential drawbacks. It means that a copy of the image is kept only in GPU memory, which might go away in some scenarios (disconnecting an external GPU, disconnecting a remote desktop session, updating graphics drivers, etc.). Therefore, we recommend that you only change this flag on images that are temporary, or when it’s possible to completely recreate the image on-demand.
There’s a new example showing the backup API in use in the GraphicsDemo:
Is there, or will there be, a place we can go for tips migrating from JUCE 7x to 8x? It’s great that the performance problems are being worked on and addressed, but it’s difficult to collate from a bunch of posts across different threads on the forum.
With Reuben and Matt’s help, I cleaned up the official Direct2D Feature Overview to account for changes since initial release.
I clarified that workarounds (like avoiding get/setPixelAt, needing to scope the Graphics context when manually setting pixels, avoiding setBufferedToImage) are no longer needed.
I also added an “Improvements since initial release” section at the bottom and will continue to maintain that.
Outside of those resolved issues/workarounds and the “Golden Rules” in the feature overview, I’m not aware of any more tips needed to upgrade — but I’m happy to add any if people have them.
AFAICT it is safe (at least it won’t freeze the DAW now) but it may not perform as well as software rendering under some scenarios or on some machines. The develop branch has some improvements on images and shadows. I would like to know what JUCE team thinks of the Matt direct2d-2025 branch and whether we will see more improvements in JUCE 8.0.7. For example, the following bug fix is on Matt’s branch but not on JUCE develop branch yet:
Yes, we’re aware that there are some fixes we still need to incorporate. We’re working on it, but the team is quite busy with other work at the moment so I’m not sure how quickly we’ll be able to get everything merged.
A follow up on this: I finally have time to try the matt direct2d-2025. My plugin is an equalizer that uses draw/fill path extensively with a large background (buffered to image). And I build three versions:
version 1: with JUCE 8.0.6
version 2: with tip of JUCE develop
version 3: with matt direct2d-2025
The difference between GUI performance is obvious: version 1 < version 2 < version 3. version 3 takes noticeably less CPU when I drag a filter (i.e., when the filter magnitude response curve gets updated & repainted rapidly). And I can see version 3 is almost as smooth as the plugin on macOS, which is what I have been waiting for since the first beta release of JUCE Direct2D feature.
I don’t risk updating more of our plugins to 8.0.6 because of performance problems that can happen in some situations. @zsliu98 post shows that JUCE 8.0.6 is still slower than the software renderer for a usual scenario.
It looks like the changes by @matt finally improved performance. It would be great to see them soon in the next JUCE master update. Please prioritize this if possible.
Good to hear matters have improved. I’m still looking at issues with clipping with large numbers of sibling components, and drawing rectangle lists with many rectangles.
✓ works: buffer all sliders & buttons that may get repainted when I drag a eq band
✓ works: update the position of the dragger under a certain refresh rate instead of link it directly with a parameter (to avoid too many repaint calls above the refresh rate)
✗ not work: buffer eq curves to images, probably because pure strokePath is relatively fast for Direct2D. It may get improved if I can cache the juce::Path to GPU.
You mean using strokePath directly is always faster, even if the path is not updated?
By init you mean each time the editor is open?
That is good to hear as that was a serious shortcoming in term of fluidity of the workflow for the end user. Is it still slower than JUCE 7?
At least I didn’t notice a clear difference. Several days ago when I looked at the code of strokePath:
I thought that I could improve path painting by creating the strokedPath once and fillPath repeatedly. However, it seems that CoreGrpahics & Direct2D are really good at drawing the path directly. I haven’t dived into those native contexts code yet. Path updating is on a background thread so it doesn’t matter here.
By init you mean each time the editor is open?
Yes, I mean the time it takes to open the editor.
That is good to hear as that was a serious shortcoming in term of fluidity of the workflow for the end user. Is it still slower than JUCE 7?
If you optimize the code (the most important trick seems to be using setBufferedToImage wisely), it is possible to be better than JUCE 7. For example, with JUCE 7 painting 16 EQ curves may slow down the DAW/plugin interface significantly (even at a low fps). However, with JUCE 8 everything is smooth (even with a gradient on the spectrum).
For sure, and my current UI runs significantly better on JUCE 8.0.6 D2D than it did on JUCE7 as well.
I was specifically referring to the loading time here though, especially on slow/old machines.