OpenGL on Windows is a little notorious for showing high CPU usage even if you’re just drawing a single triangle. This has always been annoying because it makes your plug-in look bad even if it has no actual performance impact. The cause relates to SwapBuffer() waiting for the GPU but appearing to occupy CPU in the meanwhile (even though apparently it doesn’t actually do any work on the CPU).
Found some posts online mentioning the use of DwmFlush immediately after SwapBuffers as a work-around for this issue. Tried it and it actually does work. CPU usage reports as much lower while actual performance is the same.
Has anyone else messed around with this issue, in particular with this DwmFlush work-around?
You can try it using the snippet below if anyone else wants to try. Just place an instance of this class inside your OpenGL class and call ::flush at the start of each OpenGL frame (this is effectively the same as “after” SwapBuffers because of how the JUCE OpenGL rendering thread works).
#if JUCE_WINDOWS
// helper class to flush DWM, drastically reducing reported CPU usage
class DWMFlusher
{
public:
DWMFlusher()
{
// Load dwmapi.dll dynamically
dwmapiLibrary.open("dwmapi.dll");
if (dwmapiLibrary.getNativeHandle() != nullptr) {
// Get the address of the DwmFlush function
dwmFlushFunction = reinterpret_cast<DwmFlushType>(dwmapiLibrary.getFunction("DwmFlush"));
}
}
~DWMFlusher() { dwmapiLibrary.close(); }
void flush()
{
if (dwmFlushFunction) {
dwmFlushFunction();
}
}
private:
using DwmFlushType = HRESULT(WINAPI*)();
juce::DynamicLibrary dwmapiLibrary;
DwmFlushType dwmFlushFunction = nullptr;
};
#else
// dummy class for non-windows platforms
class DWMFlusher
{
public:
DWMFlusher() {}
~DWMFlusher() {}
void flush() {}
};
#endif