Lock up when going fullscreen on Big Sur

Since Big Sur our application locks up when the user chooses to set the MainWindow to fullscreen using the green ‘fullscreen’ button using the native title bar.
The lock up only happens when the MessageThread is quite busy.

So to rule out it’s actually our own code that is causing this i created a basic GUI application (straight out of the Projucer with the latest version of JUCE v6.0.7) and added some code it to trigger this behaviour.

I modified the paint routine to draw 500 rectangles, i set a Timer to fire at 15hz to cause frequent repaints (to be honest on my machine the Timer isn’t even needed it locks up without it as well). When you press the green ‘fullscreen’ button the whole screen goes black and the Window which has a red background will stay in the middle, see attached screenshot. If i only draw 1 rectangle it works fine and the result is a red window covering the whole screen without window decorations.

So to be very clear, this is vanilla JUCE GUI app, straight from the Projucer with the latest version. No extra code added whatsoever. Please have a look at this a.s.a.p, because this is a serious issue.

//==============================================================================
MainComponent::MainComponent()
{
    setSize (600, 400);
    startTimerHz(15);
}

MainComponent::~MainComponent()
{
}

//==============================================================================
void MainComponent::paint (juce::Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));

    g.setFont (juce::Font (16.0f));
    g.setColour (juce::Colours::white);
    g.drawText ("Hello World!", getLocalBounds(), juce::Justification::centred, true);
    
    for (int i=0; i<500;i++)
    {
        g.setColour(juce::Colours::red);
        g.fillRect(getLocalBounds());
    }
}

void MainComponent::resized()
{
    // This is called when the MainComponent is resized.
    // If you add any child components, this is where you should
    // update their positions.
}

void MainComponent::timerCallback()
{
    
    repaint();
}

Follow ups:

  • If the behaviour isn’t triggered directly, please fire the timer more often or draw more rectangles, it turned out i didn’t even need to run a timer.
  • I know you had issues with the painting being slow on Big Sur and i’m aware of the fix you have on develop for this (using the kCAContentsFormatRGBA8Uint). We use that fix successfully in our app, this can cause this behaviour to not manifest itself directly, but if more strain is put on the Message Thread the same issue will manifest itself eventually.

You know what’s so strange about this bug. If i instead of filling 500 rects i draw a text randomly on screen 5000 times the fullscreen behaviour still works, the UI seems to be struggling much more than with the rects (which is expected) but it does properly switch to fullscreen mode eventually.

for (int i=0; i<5000;i++)
{
    g.setColour(juce::Colours::red);
    //g.fillRect(getLocalBounds());
    
    juce::Random rnd;
    int x = rnd.nextInt(juce::Range<int>(0, getWidth()));
    int y = rnd.nextInt(juce::Range<int>(0, getHeight()));
    g.drawText("Testing", x, y, 200, 200, juce::Justification::topLeft);
}

I paused the process to look at the call-stack in Xcode. The call-stack is small but shows OSX is busy performing a CGSFillDRAM64.

Doing a simple search this is the topic that pops up:

Does the above ring any bells to anyone?

Which version of Big Sur are you using? On Big Sur 11.0.1 beta, I see similar behaviour, but not quite the same. Specifically, when I enter full screen, the window remains its old size for a second or so, before the screen is completely filled with red. This seems to be the case whether I set the timer to 60Hz, or disable it completely.

If I profile the app, and then open it, fullscreen it, and quit it, the profile shows that around 60% of the time is spent in CGContextFillRect. This isn’t massively surprising - we ask CoreGraphics to render lots of rectangles, and that’s what it does. The time-consuming stuff all happens inside CoreGraphics.

If I enable JUCE_COREGRAPHICS_DRAW_ASYNC=1 and profile again, the time spent in CoreGraphics drops a bit, and the resizing happens much more quickly too (the window doesn’t get lost in the middle of the screen for a few seconds), with or without the timer running at 60Hz. If you haven’t been using this option, I’d recommend enabling it and seeing whether it helps at all.

I’ll try updating my machine to a more recent release of Big Sur over lunch, and I’ll check whether this has any effect on the behaviour.

It’d be helpful if you could try pausing the debugger when you see the ‘lock up’ behaviour, and posting the call stacks for all threads.

I’ve tested 11.3 beta now too, and I see identical behaviour there. I’m currently unable to reproduce any kind of lockup.

Hi @reuk , thank you for looking into this. I’m running Big Sur 11.2.

Here are the call-stacks.

CGContextFillRect shows up in my call-stack only when the kCAContentsFormatRGBA8Uint format is set, i’m guessing you are not using v6.07 but the develop branch?

If kCAContentsFormatRGBA8Uint is not set this is the call-stack i get:

I tried the JUCE_COREGRAPHICS_DRAW_ASYNC=1 flag, and that definitely improves things but it does only postpone the problem, eventually it will freeze when UI get’s really busy.

For the record, this behaviour is not present in our application on OSX versions prior to Big-Sur.

Here is a Video that shows the behaviour in our software, software runs fine and is responsive until fullscreen.

OK, I’ve now tested the same app on an older machine running 11.2 - even without DRAW_ASYNC I don’t get any lockup on that machine. I’ve been using the develop branch for all tests.

The reason I’d asked for the stack traces was that I wondered whether there was a rare deadlock somewhere. However, from the traces you’ve provided it doesn’t look like the main thread is waiting on a lock in either case.

Without being able to repro the issue, it’s difficult to say what the root cause might be, but at the moment it looks like an OS-level problem rather than an issue in JUCE. It might be interesting to try creating a plain non-JUCE app which just paints the entire window red (like your demo) to see whether that behaves in the same way. I’ve attached a little non-JUCE Xcode project which you can test out. For me, this takes a few seconds to enter fullscreen, so perhaps this will lock up on your system too.

redscreen.zip (78.3 KB)

Thanks again for putting in the time @reuk, was about to create a similar app to see if it isn’t actually an OS thing.

And yes indeed the app you created has similar behaviour, both of the apps (JUCE and Swift) always seems to be able to come back out of fullscreen though if you are patient enough it seems. JUCE has much more trouble though, but that might be expected.

Somehow our own Application has troubles recovering from fullscreen mode. In the video is sent you can see that the fullscreen behaviour is executed properly en UI is nice and responsive util fullscreen is executed.

Hmmm, don’t know where to start looking next, Big Sur really is causing some serious issues for us.

1 Like

Alright i found a solution that works for us. We always return true in shouldThrottleRepaint (in juce_mac_NSViewComponentPeer), this prevents the Drawing Thread going crazy. Somehow when app goes fullscreen all drawings commands seem to queue up and MessageThread struggles to get them all handled. It looks like a OS thing but at the same time we should probably prevent invoking too many paint calls. This throttling is also a solution if you have poor drawing performance in your app. So until we or you have a better solution we stick with this one.