GUI Drawing Efficiency


#1

Hi Jules and team,

I have been noticing recently that my GUIs with meters or graphs (i.e. which have sections which are redrawing regularly) have a very obvious effect on the host drawing. One instance is usually fine, two is passable, but any more than this severally lags the host’s own drawing. I suspect this behaviour is due to all of the drawing been handled by the same message thread which just gets overwhelmed with the amount of drawing required.

Comparing to plug-ins written using VST GUI it is clearly not an issue for them, which is slightly concerning. Are there any improvements to this upcoming in JUCE 4 or planned for the future? I’m aware that using OpenGL will certainly help the matter, but from what I can see there isn’t a way to use an OpenGL Graphics context to pass down through the paint methods.

Any improvements in this area would be really appreciated!

Cheers,

Luke.


#2

mmmh, I've the same issue on mac, I've tried coreimage, juceimage and opengl but the CPU load still high, you can noticed lags on sliders and vumeter (drawImage with filmstrip) if you open the gui of several plugin instances at the same time.

I've removed timers and listeners from AudioProcessorEditor but the problem persisted. I've set JUCE_ENABLE_REPAINT to check if there is a unwanted repaint. So I don't think is a drawimage problem or any repaint.

 

 

 

  

 


#3

Comparing to plug-ins written using VST GUI it is clearly not an issue for them, which is slightly concerning.

It's painful when we see people post things like this - it creates unfair FUD around juce's drawing code! There are plenty of juce-based metering apps out there that perform very well, but you can't just approach something like this naively and expect the framework to magically make your code run fast - getting good graphics performance requires some careful work on any framework.

The juce rendering engines are very fast - at least as fast as anything you'll get in VSTGUI or other frameworks.

Are there any improvements to this upcoming in JUCE 4 or planned for the future?

Interesting question!

- The CoreGraphics renderer: Impossible to improve it, because it's obviously bottlenecked by the performance of CoreGraphics itself.

- The software renderer: Can't be improved, because although its compositing code could probably have a few more percentage-points squeezed out of it, on modern devices it's entirely bottlenecked by the huge memory bandwidth required to get high-res bitmaps onto the screen. CPU-based rendering is simply not a feasible option for retina-size displays now.

- The openGL renderer: This is already very fast, but it's bottleneck is in the time taken to rasterise paths, which isn't a task that can be moved onto the GPU, so there's not really anything else we can do to make this faster.

But.... New post-openGL frameworks are appearing like Metal and Vulkan, and we'll be able to write some crazily-fast rendering engines for these APIs. We're looking forward to working on that, it'll be a fun programming challenge!

But to answer your problem - just like for any performance-related problem the answer is always:

PROFILE YOUR APP!

There's really no point in asking for help until you understand where your CPU is being used, and the results are almost always surprising.

I’m aware that using OpenGL will certainly help the matter, but from what I can see there isn’t a way to use an OpenGL Graphics context to pass down through the paint methods.

If you're drawing bitmap images, the GL renderer will be faster by a ridiculous amount. Have a look at the demo app to see how you can enable GL-based rendering - it's only about 4 lines of code and a bit of messing-about to do so. (We're going to add some helper functionality soon to make it a one-line change to enable it)

 

 


OpenGL Deprecated in Mojave
#4

Jules - that was a good list of bullet points.  But you say: 

- The openGL renderer: This is already very fast, but its bottleneck is in the time taken to rasterise paths, which isn't a task that can be moved onto the GPU.

From my playing with OpenGL, I thought rasterising stuff was a mainstream activity for it.  Taking a series of positions and sorts out all the pixel shit. 

Which bit are you referring to ? 


#5

In order to draw a bezier path, it needs to be broken into triangles somehow for GL to process. The solution I opted for was to use the same scanline rasterisation algorithm as the software renderer uses, so that it's effectively building the shape out of one-pixel-high rectangles. This gives the exact same anti-aliasing as the software renderer gets, but is faster because it doesn't need to do any compositing.

The alternative way to do it is to triangulate the path, but that's really not much easiler in terms of algorithmic complexity, and although it's fewer triangles for the GPU to handle, it means that the only way to anti-alias is relies on the GPU multi-sampling, which isn't available (or very good) on all devices.

But in either method the bottleneck is the CPU flattening beziers into something the GPU can process.. Ideally, we'd like to just throw the raw bezier data at the GPU and let it handle it while the CPU does something else, but GLSL isn't built for that kind of task. It can be done with openCL, but that's not available on all devices.. The next-gen APIs will be better though - AFAICT Metal/Vulkan are a bit more openCL-like, so we should be able to build a really great renderer on there.


Are there any games built with JUCE?
#6

Ah .... :)


#7

Afaict, NanoVG does this portably and might work out as a GL render backend. 


#8

AFAIK it doesn't anti-alias like JUCE does. And it will have the same bottleneck I described above - i.e. the path flattening or tesselating must be done on the CPU. All openGL 2D renderers will have this issue - it's unlikely that any other library could be significantly faster than JUCE, because GL just isn't built for it.


#9

Yes, i see, thanks for clarifications.
I hope to find time to hack together a NanoVG render backend just to see what it looks and performs like with an existing juce application.


#10

Hi Jules, 

The drawing is not the problem, I can draw/repaint images very efficiently using coreimage and juce native.

I've created a test plugin with 250 sliders with listeners, and runs very smooth without lags.
Then another plugin with 5 sliders, but this time I've created 30 instances in reaper, when I start to open their guis, sliders starts to lag, if you open all instances gui, the lag is very noticeable.

so I don't think it's a problem with the paint components, for me, the render engine is fast


#11

Well it's presumably the host or OS repaint schedule adding some kind of overhead.

But like I've said hundreds of times before on this forum: The only way to investigate this kind of thing is to USE A PROFILER to measure what's actually happening!


#12

Thanks Jules, 

I'll see if I can identify where the bottleneck is, I've never used a profiler yet,  when I have some time I will look at this.


#13

as you said you tested in reaper, perhaps that could be related : http://forum.cockos.com/showthread.php?t=165227


#14

Yes, 

I noticed that reaper vst2 plugin gui gets continuously repainted a rectangle on the bottom part of the gui, 

I've done the same test with vst3 (30 gui instances) and all run smoothly... I've tested too a plugin with a big VU meter (bitmap based) and run all smooth with 30 gui instances opened.

So, isn't a juce problem... 


#15

Juce Plugin Host process from "activity Monitor" %CPU,  10 plugin instances (with gui opened):

VST2: 30.1% CPU

VST3: 6% CPU 

Macbook pro mid 2014, i5, 8gb ram, ssd disk, osx 10.9. 

Base sdk 10.10, comp 10.7, release build with fastest optimizations, coreimage.

 

Sorry, for now I will not profile because I don't know how yet, but when I get some free time, I will investigate it


#16

I think I found the problem, 

on VST 2.4 AudioProcessor::createEditor() gets called twice when you open the plugin gui.

You can reproduce it in Juce Demo Plugin: AudioProcessorEditor* JuceDemoPluginAudioProcessor::createEditor();

Edit: apparently this is normal,  http://www.juce.com/forum/topic/plugineditor-ctor

 


#17

Profilers are super-awesome.  Click, run, ohhhhhh ....:)


#18

Yes - there's really no point in spending time looking at a performance problem unless you profile it. Looking at the numbers in Activity Monitor won't tell you much.


#19

Does this still hold true?


#20

Yeah, pretty much.