Browse Source

OpenGL: Ensure that GL views display at the correct scale on macOS 12

Previously, we were using the window's top-left position to determine
the scale to use for the OpenGLContext. However, on macOS the
backingScaleFactor of the window is not strictly related to the top-left
corner of the window, so the OpenGL view's scale could end up differing
from the backing scale factor when slowly moving a window between
displays with different backing scale factors.

On macOS, we now use the backing scale factor of the window's screen (as
maintained by AppKit), rather than trying to work out the correct
display and scale ourselves.
v6.1.6
reuk 3 years ago
parent
commit
ea8b0a2d32
No known key found for this signature in database GPG Key ID: FCB43929F012EE5C
1 changed files with 39 additions and 31 deletions
  1. +39
    -31
      modules/juce_opengl/opengl/juce_OpenGLContext.cpp

+ 39
- 31
modules/juce_opengl/opengl/juce_OpenGLContext.cpp View File

@@ -161,13 +161,6 @@ public:
void resume()
{
#if JUCE_MAC
initialDisplayTopLeft = Desktop::getInstance().getDisplays()
.getDisplayForRect (component.getTopLevelComponent()->getScreenBounds())
->totalArea
.getTopLeft();
#endif
if (renderThread != nullptr)
renderThread->addJob (this, false);
}
@@ -314,23 +307,26 @@ public:
if (auto* peer = component.getPeer())
{
auto localBounds = component.getLocalBounds();
const auto currentDisplay = Desktop::getInstance().getDisplays().getDisplayForRect (component.getTopLevelComponent()->getScreenBounds());
if (currentDisplay != lastDisplay)
#if JUCE_MAC
const auto displayScale = [this]
{
#if JUCE_MAC
if (cvDisplayLinkWrapper != nullptr)
if (auto* wrapper = cvDisplayLinkWrapper.get())
{
cvDisplayLinkWrapper->updateActiveDisplay (currentDisplay->totalArea.getTopLeft());
nativeContext->setNominalVideoRefreshPeriodS (cvDisplayLinkWrapper->getNominalVideoRefreshPeriodS());
if (auto* screen = wrapper->updateAndReturnActiveDisplay())
{
nativeContext->setNominalVideoRefreshPeriodS (wrapper->getNominalVideoRefreshPeriodS());
return [screen backingScaleFactor];
}
}
#endif
lastDisplay = currentDisplay;
}
const auto displayScale = currentDisplay->scale;
return scale;
}();
#else
const auto displayScale = Desktop::getInstance().getDisplays().getDisplayForRect (component.getTopLevelComponent()->getScreenBounds())->scale;
#endif
auto localBounds = component.getLocalBounds();
auto newArea = peer->getComponent().getLocalArea (&component, localBounds).withZeroOrigin() * displayScale;
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
@@ -590,7 +586,7 @@ public:
#if JUCE_MAC
cvDisplayLinkWrapper = std::make_unique<CVDisplayLinkWrapper> (*this);
cvDisplayLinkWrapper->updateActiveDisplay (initialDisplayTopLeft);
cvDisplayLinkWrapper->updateAndReturnActiveDisplay();
nativeContext->setNominalVideoRefreshPeriodS (cvDisplayLinkWrapper->getNominalVideoRefreshPeriodS());
#endif
@@ -709,13 +705,9 @@ public:
OpenGLFrameBuffer cachedImageFrameBuffer;
RectangleList<int> validArea;
Rectangle<int> viewportArea, lastScreenBounds;
const Displays::Display* lastDisplay = nullptr;
double scale = 1.0;
AffineTransform transform;
GLuint vertexArrayObject = 0;
#if JUCE_MAC
Point<int> initialDisplayTopLeft;
#endif
StringArray associatedObjectNames;
ReferenceCountedArray<ReferenceCountedObject> associatedObjects;
@@ -752,15 +744,30 @@ public:
return 0.0;
}
void updateActiveDisplay (Point<int> topLeftOfDisplay)
NSScreen* getCurrentScreen() const
{
CGDirectDisplayID displayID;
uint32_t numDisplays = 0;
constexpr uint32_t maxNumDisplays = 1;
CGGetDisplaysWithPoint (convertToCGPoint (topLeftOfDisplay), maxNumDisplays, &displayID, &numDisplays);
if (auto* peer = cachedImage.component.getPeer())
if (auto* view = static_cast<NSView*> (peer->getNativeHandle()))
if (auto* window = [view window])
return [window screen];
return nullptr;
}
/* If updated, returns the new screen, or nullptr otherwise. */
NSScreen* updateAndReturnActiveDisplay()
{
auto* oldScreen = std::exchange (currentScreen, getCurrentScreen());
if (oldScreen == currentScreen)
return nullptr;
for (NSScreen* screen in [NSScreen screens])
if (screen == currentScreen)
if (NSNumber* number = [[screen deviceDescription] objectForKey: @"NSScreenNumber"])
CVDisplayLinkSetCurrentCGDisplay (displayLink, [number unsignedIntValue]);
if (numDisplays == 1)
CVDisplayLinkSetCurrentCGDisplay (displayLink, displayID);
return currentScreen;
}
~CVDisplayLinkWrapper()
@@ -783,6 +790,7 @@ public:
CachedImage& cachedImage;
const bool continuousRepaint;
CVDisplayLinkRef displayLink;
NSScreen* currentScreen = nullptr;
};
std::unique_ptr<CVDisplayLinkWrapper> cvDisplayLinkWrapper;


Loading…
Cancel
Save