From ee976f0f0d42bd213baf94df59f0de941dab1a37 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Mar 2023 16:54:56 +0000 Subject: [PATCH] NSViewComponentPeer: Avoid using metal renderer if view has changed size since repaints were requested The main change is that the numFramesToSkipMetalRenderer member has been removed. The old mechanism had some problems in AU plugins in Logic. Specifically, when opening a temporary window, repaints would be ignored until the numFramesToSkipMetalRenderer counter had been decremented to zero. In practice, this meant that a PopupMenu might not repaint until the highlighted item had changed five times or more. With this change applied, repaints that were requested for a particular window size will use the metal renderer as long as the window hasn't changed size in the meantime. --- .../native/juce_mac_NSViewComponentPeer.mm | 57 +++++++------------ 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 970adb46b0..f77e3e308f 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -341,10 +341,7 @@ public: } if (oldViewSize.width != r.size.width || oldViewSize.height != r.size.height) - { - numFramesToSkipMetalRenderer = 5; [view setNeedsDisplay: true]; - } } Rectangle getBounds (const bool global) const @@ -1013,6 +1010,8 @@ public: // As a work around for this, we use a RectangleList to do our own coalescing of regions before // asynchronously asking the OS to repaint them. deferredRepaints.add (area.toFloat()); + const auto frameSize = view.frame.size; + boundsWhenRepaintsDeferred = { (float) frameSize.width, (float) frameSize.height }; } static bool shouldThrottleRepaint() @@ -1043,43 +1042,31 @@ public: if (msSinceLastRepaint < minimumRepaintInterval && shouldThrottleRepaint()) return; - if (metalRenderer != nullptr) - { - auto setDeferredRepaintsToWholeFrame = [this] - { - const auto frameSize = view.frame.size; - deferredRepaints = Rectangle { (float) frameSize.width, (float) frameSize.height }; - }; + const auto frameSize = view.frame.size; + const Rectangle currentBounds { (float) frameSize.width, (float) frameSize.height }; - // If we are resizing we need to fall back to synchronous drawing to avoid artefacts - if ([window inLiveResize] || numFramesToSkipMetalRenderer > 0) - { - if (metalRenderer->isAttachedToView (view)) - { - metalRenderer->detach(); - setDeferredRepaintsToWholeFrame(); - } + if (boundsWhenRepaintsDeferred != currentBounds) + { + deferredRepaints = currentBounds; - if (numFramesToSkipMetalRenderer > 0) - --numFramesToSkipMetalRenderer; - } - else - { - if (! metalRenderer->isAttachedToView (view)) - { - metalRenderer->attach (view, getComponent().isOpaque()); - setDeferredRepaintsToWholeFrame(); - } - } + if (metalRenderer != nullptr && metalRenderer->isAttachedToView (view)) + metalRenderer->detach(); + } + else + { + if (metalRenderer != nullptr && ! metalRenderer->isAttachedToView (view)) + metalRenderer->attach (view, getComponent().isOpaque()); } auto dispatchRectangles = [this] { - if (metalRenderer != nullptr && metalRenderer->isAttachedToView (view)) - return metalRenderer->drawRectangleList (view, - (float) [[view window] backingScaleFactor], - [this] (CGContextRef ctx, CGRect r) { drawRectWithContext (ctx, r); }, - deferredRepaints); + if (metalRenderer != nullptr && metalRenderer->isAttachedToView (view)) + { + return metalRenderer->drawRectangleList (view, + (float) [[view window] backingScaleFactor], + [this] (CGContextRef ctx, CGRect r) { drawRectWithContext (ctx, r); }, + deferredRepaints); + } for (auto& i : deferredRepaints) [view setNeedsDisplayInRect: makeNSRect (i)]; @@ -1704,6 +1691,7 @@ public: int startOfMarkedTextInTextInputTarget = 0; Rectangle lastSizeBeforeZoom; + Rectangle boundsWhenRepaintsDeferred; RectangleList deferredRepaints; uint32 lastRepaintTime; @@ -1946,7 +1934,6 @@ private: } //============================================================================== - int numFramesToSkipMetalRenderer = 0; std::unique_ptr> metalRenderer; std::vector scopedObservers;