OpenGL cpu usage bug?

Hi all!

Upfront, allow me to apologize for not having this completely worked out. This is just something I’ve found while being frustrated with how much CPU openGL in JUCE is using.

Simply adding a context to my plugin, and turning off all component rendering puts a high end CPU at 7% usage with no rendering and a blank, black screen.

I have found this is because of how JUCE handles the render loop with openGL, and this machine is running at 144hz, so 144 times per second, JUCE is running a bunch of heavy openGL boilerplate code, found in the renderAll() function at line 821 of juce_OpenGLContext.cpp.

This means that even if I were to create a guard within my renderOpenGL() call, to slow down how the geometry updates, this happens after the heavy calls are made.

So what I have done, in order to limit the frame rate of this context is to modify line 919 of the same file as follows:

        std::thread thread { [this]
        {
            auto last = juce::Time::currentTimeMillis();
            Thread::setCurrentThreadName ("OpenGL Renderer");
            while (flags.waitForWork (renderAll() != RenderStatus::noWork)) 
            {
                auto now = juce::Time::currentTimeMillis();
                auto timeBetween = now - last;
                if (timeBetween < 33)
                {
            	    Thread::sleep(33 - timeBetween);
                }
                last = juce::Time::currentTimeMillis();
            }
        } };

This now gives me a ~30fps render loop, without calling that heavy boilerplate needlessly inbetween frames.

CPU usage is down to 0-1%.

Is there anything to be gained here by the JUCE team to fix how hungry the OpenGL system currently is, by allowing us to specify the context target framerate?

1 Like

i have not started learning openGL yet partially because i already heard from others that it’s heavy. now seeing this is only because fps is not capped makes it look even more frustrating as i’m also convinced most people can barely tell the difference between 40 and 60 fps. most things could even run at 24 and be alright. controlling this in a clean way should definitely be added to juce. then i’d be interested in openGL too

Traditionally in games and whatnot the fps thing isn’t an issue. The frames happen when they happen, and then geometry is updated based on the time between frames. This allows player speed to be independent of framerate, for example. But in a game, you have one window, the context is made active, and then that work is done and you only have the render loop to worry about.

With JUCE though, presumably because it’s expected there may be many different windows open at any given time, JUCE appears to try to clean up after itself. When it’s render loop starts, it communicates to openGL that this plugin window is now the active context, and when it’s finished it then deactivates it. At face value this seems like a good thing. However when a system is hammering the FPS, this is potentially 100’s of activate/deactivate context calls per second, and we have no control over that.

In the game scenario you can just check to see when n milliseconds have passed to trigger that object to change to another animation set. If you do that in JUCE, you still get all these useless activation calls.

Have you enabled continuous repainting? At the moment, continuous repainting will repaint as fast as the context will allow, normally syncing with the screen refresh rate.

If you don’t want to redraw on every frame, you could consider disabling continuous repainting, and only calling repaint() when you want to draw a new frame.

Are you referring to triggerRepaint() to asynchronously fire the render? I’ve found doing this via timers to be less accurate and results in stuttering.

1 Like