I’ve noticed that one of my cores was 100% blocked when using an OpenGL context with continuous repaint turned on.
So, as an experiment, I turned the continuous repaint off, set the swap interval to 0, and used a vblank attachment to trigger a repaint. The OpenGL context now refreshes at a stable sync framerate (60 Hz in my test case), and none of my cores is hogged 100% anymore. Overall CPU consumption dropped from 8% to 2-3% (I have a 20-core system = 10 cores doubled by Hyperthreading). So one core used to 100% equals 5% load.
This is a massive improvement. Could the JUCE team replace the current “continuous repaint” logic with a simple VBlank attachment and archive the same, or at least document this discovery so future users don’t fall into the same trap?
That is definitely not the normal state, it must be a bug in the vsync detection. At least with JUCE7, it works. May I ask what hardware/OS are you using? I once had a similar phenomenon inside a Parallels instance.
I don’t see 100% core usage in the OpenGLDemo example project on macOS Arm or Windows 11.
Please provide as much detail as possible so that we can reproduce this issue. It would be helpful to have:
A minimal example project demonstrating the problem, ideally one of the JUCE examples
The OS version, graphics driver version, and full hardware spec of the machine that demonstrates the problem
The OpenGL and GLSL versions in use
We’re unlikely to make any changes in this area unless it’s possible to demonstrate a clear problem with the current implementation. In particular, it took a long time to get the current implementation working properly on macOS 10.12 with DRAW_ASYNC enabled (details here), and I’d be reluctant to make any changes that might cause regressions there.
I have seen this too, for years. It spins a thread and will repaint as fast as it possibly can. It seems to randomly stop after a while of runtime. It can also be fixed by putting a sleep at the end of each loop for a short while. I’m not sure if this is technically a bug, as in videogame word this is kind of the point of things, to be constantly updating your framebuffer as often as you can.
You can also use DwmFlush to similar effect. I think the root of the problem is that SwapBuffers for whatever reason reports as CPU usage when really it should be a wait state. Is it actually using CPU? I don’t know for sure, it might just be marked incorrectly by CPU monitors for some reason.
After adding this little DwmFlush helper class, my CPU reports as 0% most of the time, even with fairly heavy OpenGL usage.
Sorry to be harsh. I consider testing and debugging in emulations and virtualizations diagnostic malpractice. You go from having zero information to having misinformation. You’re not measuring/testing the target system; you’re measuring/testing the emulation/virtualization software.
I don’t know which video games you’ve been part of, but during my career, we’ve waited for the next v-sync once the drawing was complete, or if we were over the frame time budget, then we swapped without waiting. Otherwise, you will get tearing, which looks extremely unpleasant and distracting.
I’ve disabled it in the BIOS, don’t have drivers for it, etc.
Nvidia cards are very popular, so comparing them with Intel-integrated graphics is not very helpful (IMO). I want to make sure my solution works everywhere and with as few resources as possible.
The vBlankAttachment is a good, tested solution and this workaround works perfectly, ignoring any potential faults in the swapchain implementation of the OpenGL driver.
Your immediate guess as to the best solution isn’t automatically the brilliant perfect answer just because it works on your test machine. This type of change likely has many effects you haven’t even thought about.
Yes, I’ve changed the required version to 4.3, set the swap interval to 0, and disabled the continuous repaint, and finally added the vblankattachment. CPU usage went from 5-8% to 1-2%.
Previously one core was always at 100%, afterwards none of them were.
I also disabled the “controlOverlay”. If I leave that enabled, the framerate is worse (only 30 fps instead of 60 fps = it misses every second frame), but CPU usage was still lower.
Please don’t exaggerate for effect. Even a charitable line count comes to 22, which doesn’t include calling the flush function.
I know, but I didn’t see the point since my solution seems much more straightforward. It might have its benefits after playing with the OpenGLDemo from the JUCE examples.
Yeah, I understand. My workaround works very well for my specific project and provides enormous CPU savings, but I can now see that it’s not a one-size-fits-all solution.
I’ve managed to work around that pesky Window.h problem, and I can confirm that your solution works. Both for my project AND the DeamRunner OpenGL demo. Buttery smooth 60 fps without hogging ANY of the cores. Thank you
@reuk Yes, this includes the controls-overlay as well. You should really try it yourself. It works wonders.