How to kill Cubase with JUCE Plug-In(s) OpenGL & Some locks (Windows)

So I got this report from a user, after being able to reproduce this with our old “write shaders yourself” code I’ve went up and been able to trace this as related to JUCE Messaging and Locking.

(My machine is i7-6800k with nVidia GTX750 32GB RAM, Windows 10 and I’ve tested Cubase 9.0.1)

  1. So first create a new Audio Plug-in from Projucer (I’ve used latest development commit #daab51
    as of writing this).

  2. Add 3 lines,

  • an OpenGLContext mCtx with your private variables (Editor.h)
  • In your constructor: mCtx.attachTo(*this);
  • In your destructor: mCtx.detach()
  1. Compile and copy .dll to your vstplugins folder. (I’ve tested also VST3, it’s not a wrapper thing)

  2. Open Cubase with a new empty project.

  3. Create 32 Audio Tracks (you can do even less though)

  4. Open MixConsole (F3)

  5. Select all audio tracks (from the area on your left, shift-click)

  6. Toggle the QLink button on the upper right corner (this will duplicate your behavior to all tracks).

  7. Open the Inserts view, and Insert our shiny new plugin.

Prepare to restart your machine or at least Ctrl+Alt+Del hoping Cubase will crash before your machine totally freeze.

It is kinda tricky for me the system would stuck so it is very hard to properly profile or find a decent stack.

Profiling? Adding debugger to the blend would even make your machine freeze deeper…
Eventually after few minutes I’ve been able to get Task Manager and to discover my Debugger Monitor crashed…

With OpenGL crash:
Some threads would stuck on MessageManager::Lock::BlockingMessage::messageCallback()

With OpenGL you might see many threads with:
DeleteGL.dll!juce::OpenGLContext::NativeContext::deactivateCurrentContext() Line 100|C++| | |DeleteGL.dll!juce::OpenGLContext::deactivateCurrentContext() Line 947|C++| | |DeleteGL.dll!juce::OpenGLContext::CachedImage::renderFrame() Line 276|C++| | |DeleteGL.dll!juce::OpenGLContext::CachedImage::runJob() Line 463|C++| | |DeleteGL.dll!juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread & thread) Line 389|C++| | |DeleteGL.dll!juce::ThreadPool::ThreadPoolThread::run() Line 37|C++| | |DeleteGL.dll!juce::Thread::threadEntryPoint() Line 96|C++| | |DeleteGL.dll!juce::juce_threadEntryPoint(void * userData) Line 119|C++|


It’s been with JUCE for a lot of years now. Tested our JUCE 3.x plugins, our JUCE 4.2 ones. All till latest master would behave the same.

Without OpenGL:

Without using OpenGL you’ll feel some freezing and responsiveness issues but it won’t make your machine freeze.

A Cubase issue?
I’ve tested the same workflow with Waves plug-ins. They handles it without a problem. (they do use OpenGL)

Wonder how I can continue further. it’s definitely some nasty racing / message bombarding. but it’s tricky to nail down.

Update #1:
Apparently I didn’t copy the non-OpenGL dll the first time. so I’ve updated this post to properly mention OpenGL as part of the blame.

Update #2:
On macOS this won’t reproduce.


Did you happen to figure out the issues behind this or how to work around them? We’re running into an issue on Windows that seems related.

In our plugins we have OpenGLRenderers that get updated every 40Hz or so to draw spectrum displays. The OpenGLContext in this case is just limited to the graph component drawing the spectrum analyzer (and the EQ curve, EQ band controls, etc.).

On macOS we have no issues, like your post describes, but on Windows if you open up two of our plugins the spectrum rendering causes the main thread to just stop responding. When we debug we have similar behavior to what you described:

The first plugin will actually continue rendering its display, but the main thread won’t work at all (pressing buttons, trying to move windows around, etc.).

If we disable acquiring the MessageManager::Lock during juce::OpenGLContext::CachedImage::renderFrame() - so that only our spectrum gets updated and the component painting doesn’t happen - multiple instances of our plugin run very smoothly…

…but then the main thread hanging occurs when inserting any of our older LV2 plugins, who do their whole UI in OpenGL rendering explicitly on the main thread.