Przeglądaj źródła

[macOS, 3.2] Implement seamless display scaling.

bruvzg 5 lat temu
rodzic
commit
e9ab41b71d

+ 10 - 0
core/bind/core_bind.cpp

@@ -320,6 +320,14 @@ int _OS::get_screen_dpi(int p_screen) const {
 	return OS::get_singleton()->get_screen_dpi(p_screen);
 }
 
+float _OS::get_screen_scale(int p_screen) const {
+	return OS::get_singleton()->get_screen_scale(p_screen);
+}
+
+float _OS::get_screen_max_scale() const {
+	return OS::get_singleton()->get_screen_max_scale();
+}
+
 Point2 _OS::get_window_position() const {
 	return OS::get_singleton()->get_window_position();
 }
@@ -1252,6 +1260,8 @@ void _OS::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_screen_position", "screen"), &_OS::get_screen_position, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("get_screen_size", "screen"), &_OS::get_screen_size, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("get_screen_dpi", "screen"), &_OS::get_screen_dpi, DEFVAL(-1));
+	ClassDB::bind_method(D_METHOD("get_screen_scale", "screen"), &_OS::get_screen_scale, DEFVAL(-1));
+	ClassDB::bind_method(D_METHOD("get_screen_max_scale"), &_OS::get_screen_max_scale);
 	ClassDB::bind_method(D_METHOD("get_window_position"), &_OS::get_window_position);
 	ClassDB::bind_method(D_METHOD("set_window_position", "position"), &_OS::set_window_position);
 	ClassDB::bind_method(D_METHOD("get_window_size"), &_OS::get_window_size);

+ 2 - 0
core/bind/core_bind.h

@@ -178,6 +178,8 @@ public:
 	virtual Point2 get_screen_position(int p_screen = -1) const;
 	virtual Size2 get_screen_size(int p_screen = -1) const;
 	virtual int get_screen_dpi(int p_screen = -1) const;
+	virtual float get_screen_scale(int p_screen = -1) const;
+	virtual float get_screen_max_scale() const;
 	virtual Point2 get_window_position() const;
 	virtual void set_window_position(const Point2 &p_position);
 	virtual Size2 get_max_window_size() const;

+ 2 - 0
core/os/os.h

@@ -209,6 +209,8 @@ public:
 	virtual Point2 get_screen_position(int p_screen = -1) const { return Point2(); }
 	virtual Size2 get_screen_size(int p_screen = -1) const { return get_window_size(); }
 	virtual int get_screen_dpi(int p_screen = -1) const { return 72; }
+	virtual float get_screen_scale(int p_screen = -1) const { return 1.0; }
+	virtual float get_screen_max_scale() const { return 1.0; };
 	virtual Point2 get_window_position() const { return Vector2(); }
 	virtual void set_window_position(const Point2 &p_position) {}
 	virtual Size2 get_max_window_size() const { return Size2(); };

+ 20 - 0
doc/classes/OS.xml

@@ -362,6 +362,15 @@
 				[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. Returns [code]72[/code] on unsupported platforms.
 			</description>
 		</method>
+		<method name="get_screen_max_scale" qualifiers="const">
+			<return type="float">
+			</return>
+			<description>
+				Return the greatest scale factor of all screens.
+				[b]Note:[/b] On macOS returned value is [code]2.0[/code] if there is at least one hiDPI (Retina) screen in the system, and [code]1.0[/code] in all other cases.
+				[b]Note:[/b] This method is implemented on macOS.
+			</description>
+		</method>
 		<method name="get_screen_position" qualifiers="const">
 			<return type="Vector2">
 			</return>
@@ -371,6 +380,17 @@
 				Returns the position of the specified screen by index. If [code]screen[/code] is [/code]-1[/code] (the default value), the current screen will be used.
 			</description>
 		</method>
+		<method name="get_screen_scale" qualifiers="const">
+			<return type="float">
+			</return>
+			<argument index="0" name="screen" type="int" default="-1">
+			</argument>
+			<description>
+				Return the scale factor of the specified screen by index. If [code]screen[/code] is [/code]-1[/code] (the default value), the current screen will be used.
+				[b]Note:[/b] On macOS returned value is [code]2.0[/code] for hiDPI (Retina) screen, and [code]1.0[/code] for all other cases.
+				[b]Note:[/b] This method is implemented on macOS.
+			</description>
+		</method>
 		<method name="get_screen_size" qualifiers="const">
 			<return type="Vector2">
 			</return>

+ 4 - 0
editor/editor_node.cpp

@@ -5652,8 +5652,12 @@ EditorNode::EditorNode() {
 		switch (display_scale) {
 			case 0: {
 				// Try applying a suitable display scale automatically
+#ifdef OSX_ENABLED
+				editor_set_scale(OS::get_singleton()->get_screen_max_scale());
+#else
 				const int screen = OS::get_singleton()->get_current_screen();
 				editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+#endif
 			} break;
 
 			case 1: {

+ 18 - 11
editor/editor_run.cpp

@@ -112,22 +112,31 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 	}
 
 	int window_placement = EditorSettings::get_singleton()->get("run/window_placement/rect");
+	bool hidpi_proj = ProjectSettings::get_singleton()->get("display/window/dpi/allow_hidpi");
+	int display_scale = 1;
+	if (OS::get_singleton()->is_hidpi_allowed()) {
+		if (hidpi_proj) {
+			display_scale = 1; // Both editor and project runs in hiDPI mode, do not scale.
+		} else {
+			display_scale = OS::get_singleton()->get_screen_max_scale(); // Editor is in hiDPI mode, project is not, scale down.
+		}
+	} else {
+		if (hidpi_proj) {
+			display_scale = (1.f / OS::get_singleton()->get_screen_max_scale()); // Editor is not in hiDPI mode, project is, scale up.
+		} else {
+			display_scale = 1; // Both editor and project runs in lowDPI mode, do not scale.
+		}
+	}
+	screen_rect.position /= display_scale;
+	screen_rect.size /= display_scale;
 
 	switch (window_placement) {
 		case 0: { // top left
-
 			args.push_back("--position");
 			args.push_back(itos(screen_rect.position.x) + "," + itos(screen_rect.position.y));
 		} break;
 		case 1: { // centered
-			int display_scale = 1;
-#ifdef OSX_ENABLED
-			if (OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000) {
-				display_scale = 2;
-			}
-#endif
-
-			Vector2 pos = screen_rect.position + ((screen_rect.size / display_scale - desired_size) / 2).floor();
+			Vector2 pos = screen_rect.position + ((screen_rect.size - desired_size) / 2).floor();
 			args.push_back("--position");
 			args.push_back(itos(pos.x) + "," + itos(pos.y));
 		} break;
@@ -142,10 +151,8 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
 			args.push_back("--position");
 			args.push_back(itos(pos.x) + "," + itos(pos.y));
 			args.push_back("--maximized");
-
 		} break;
 		case 4: { // force fullscreen
-
 			Vector2 pos = screen_rect.position;
 			args.push_back("--position");
 			args.push_back(itos(pos.x) + "," + itos(pos.y));

+ 4 - 3
editor/project_manager.cpp

@@ -2406,8 +2406,12 @@ ProjectManager::ProjectManager() {
 		switch (display_scale) {
 			case 0: {
 				// Try applying a suitable display scale automatically
+#ifdef OSX_ENABLED
+				editor_set_scale(OS::get_singleton()->get_screen_max_scale());
+#else
 				const int screen = OS::get_singleton()->get_current_screen();
 				editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+#endif
 			} break;
 
 			case 1: editor_set_scale(0.75); break;
@@ -2425,11 +2429,8 @@ ProjectManager::ProjectManager() {
 		// Define a minimum window size to prevent UI elements from overlapping or being cut off
 		OS::get_singleton()->set_min_window_size(Size2(750, 420) * EDSCALE);
 
-#ifndef OSX_ENABLED
-		// The macOS platform implementation uses its own hiDPI window resizing code
 		// TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
 		OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE));
-#endif
 	}
 
 	FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));

+ 2 - 10
platform/osx/os_osx.h

@@ -145,16 +145,6 @@ public:
 
 	CrashHandler crash_handler;
 
-	float _mouse_scale(float p_scale) {
-		if (_display_scale() > 1.0)
-			return p_scale;
-		else
-			return 1.0;
-	}
-
-	float _display_scale() const;
-	float _display_scale(id screen) const;
-
 	void _update_window();
 
 	int video_driver_index;
@@ -269,6 +259,8 @@ public:
 	virtual Point2 get_screen_position(int p_screen = -1) const;
 	virtual Size2 get_screen_size(int p_screen = -1) const;
 	virtual int get_screen_dpi(int p_screen = -1) const;
+	virtual float get_screen_scale(int p_screen = -1) const;
+	virtual float get_screen_max_scale() const;
 
 	virtual Point2 get_window_position() const;
 	virtual void set_window_position(const Point2 &p_position);

+ 81 - 57
platform/osx/os_osx.mm

@@ -105,11 +105,11 @@ static int mouse_y = 0;
 static int button_mask = 0;
 static bool mouse_down_control = false;
 
-static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFactor) {
+static Vector2 get_mouse_pos(NSPoint locationInWindow) {
 
 	const NSRect contentRect = [OS_OSX::singleton->window_view frame];
 	const NSPoint p = locationInWindow;
-	const float s = OS_OSX::singleton->_mouse_scale(backingScaleFactor);
+	const float s = OS_OSX::singleton->get_screen_max_scale();
 	mouse_x = p.x * s;
 	mouse_y = (contentRect.size.height - p.y) * s;
 	return Vector2(mouse_x, mouse_y);
@@ -317,11 +317,11 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
 	OS_OSX::singleton->zoomed = false;
 
 	if (OS_OSX::singleton->min_size != Size2()) {
-		Size2 size = OS_OSX::singleton->min_size / OS_OSX::singleton->_display_scale();
+		Size2 size = OS_OSX::singleton->min_size / OS_OSX::singleton->get_screen_max_scale();
 		[OS_OSX::singleton->window_object setContentMinSize:NSMakeSize(size.x, size.y)];
 	}
 	if (OS_OSX::singleton->max_size != Size2()) {
-		Size2 size = OS_OSX::singleton->max_size / OS_OSX::singleton->_display_scale();
+		Size2 size = OS_OSX::singleton->max_size / OS_OSX::singleton->get_screen_max_scale();
 		[OS_OSX::singleton->window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
 	}
 
@@ -344,7 +344,7 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
 
 	if (newBackingScaleFactor != oldBackingScaleFactor) {
 		//Set new display scale and window size
-		float newDisplayScale = OS_OSX::singleton->is_hidpi_allowed() ? newBackingScaleFactor : 1.0;
+		float newDisplayScale = OS_OSX::singleton->get_screen_max_scale();
 
 		const NSRect contentRect = [OS_OSX::singleton->window_view frame];
 		const NSRect fbRect = contentRect;
@@ -352,6 +352,14 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
 		OS_OSX::singleton->window_size.width = fbRect.size.width * newDisplayScale;
 		OS_OSX::singleton->window_size.height = fbRect.size.height * newDisplayScale;
 
+		if (OS_OSX::singleton->context) {
+			GLint dim[2];
+			dim[0] = OS_OSX::singleton->window_size.width;
+			dim[1] = OS_OSX::singleton->window_size.height;
+			CGLSetParameter((CGLContextObj)[OS_OSX::singleton->context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]);
+			CGLEnable((CGLContextObj)[OS_OSX::singleton->context CGLContextObj], kCGLCESurfaceBackingSize);
+		}
+
 		//Update context
 		if (OS_OSX::singleton->main_loop) {
 			//Force window resize event
@@ -366,10 +374,18 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
 	const NSRect contentRect = [OS_OSX::singleton->window_view frame];
 	const NSRect fbRect = contentRect;
 
-	float displayScale = OS_OSX::singleton->_display_scale();
+	float displayScale = OS_OSX::singleton->get_screen_max_scale();
 	OS_OSX::singleton->window_size.width = fbRect.size.width * displayScale;
 	OS_OSX::singleton->window_size.height = fbRect.size.height * displayScale;
 
+	if (OS_OSX::singleton->context) {
+		GLint dim[2];
+		dim[0] = OS_OSX::singleton->window_size.width;
+		dim[1] = OS_OSX::singleton->window_size.height;
+		CGLSetParameter((CGLContextObj)[OS_OSX::singleton->context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]);
+		CGLEnable((CGLContextObj)[OS_OSX::singleton->context CGLContextObj], kCGLCESurfaceBackingSize);
+	}
+
 	if (OS_OSX::singleton->main_loop) {
 		Main::force_redraw();
 		//Event retrieval blocks until resize is over. Call Main::iteration() directly.
@@ -408,9 +424,7 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
 
 - (void)windowDidBecomeKey:(NSNotification *)notification {
 	if (OS_OSX::singleton->get_main_loop()) {
-		get_mouse_pos(
-				[OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream],
-				[OS_OSX::singleton->window_view backingScaleFactor]);
+		get_mouse_pos([OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream]);
 		OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y));
 
 		OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
@@ -555,7 +569,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
 	const NSRect contentRect = [OS_OSX::singleton->window_view frame];
-	float displayScale = OS_OSX::singleton->_display_scale();
+	float displayScale = OS_OSX::singleton->get_screen_max_scale();
 	NSRect pointInWindowRect = NSMakeRect(OS_OSX::singleton->im_position.x / displayScale, contentRect.size.height - (OS_OSX::singleton->im_position.y / displayScale) - 1, 0, 0);
 	NSPoint pointOnScreen = [[OS_OSX::singleton->window_view window] convertRectToScreen:pointInWindowRect].origin;
 
@@ -678,8 +692,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
 
 	Ref<InputEventMouseButton> mb;
 	mb.instance();
-	const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
-	const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
+	const Vector2 pos = get_mouse_pos([event locationInWindow]);
 	get_key_modifier_state([event modifierFlags], mb);
 	mb->set_button_index(index);
 	mb->set_pressed(pressed);
@@ -766,8 +779,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
 	mm.instance();
 
 	mm->set_button_mask(button_mask);
-	const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
-	const Vector2 pos = get_mouse_pos(mpos, backingScaleFactor);
+	const Vector2 pos = get_mouse_pos(mpos);
 	mm->set_position(pos);
 	mm->set_pressure([event pressure]);
 	if ([event subtype] == NSEventSubtypeTabletPoint) {
@@ -776,7 +788,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
 	}
 	mm->set_global_position(pos);
 	mm->set_speed(OS_OSX::singleton->input->get_last_mouse_speed());
-	const Vector2 relativeMotion = Vector2(delta.x, delta.y) * OS_OSX::singleton->_mouse_scale(backingScaleFactor);
+	const Vector2 relativeMotion = Vector2(delta.x, delta.y) * OS_OSX::singleton->get_screen_max_scale();
 	mm->set_relative(relativeMotion);
 	get_key_modifier_state([event modifierFlags], mm);
 
@@ -855,7 +867,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
 	Ref<InputEventMagnifyGesture> ev;
 	ev.instance();
 	get_key_modifier_state([event modifierFlags], ev);
-	ev->set_position(get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]));
+	ev->set_position(get_mouse_pos([event locationInWindow]));
 	ev->set_factor([event magnification] + 1.0);
 	OS_OSX::singleton->push_input(ev);
 }
@@ -1336,7 +1348,7 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) {
 - (void)scrollWheel:(NSEvent *)event {
 	double deltaX, deltaY;
 
-	get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]);
+	get_mouse_pos([event locationInWindow]);
 
 	deltaX = [event scrollingDeltaX];
 	deltaY = [event scrollingDeltaY];
@@ -1509,8 +1521,10 @@ static void keyboard_layout_changed(CFNotificationCenterRef center, void *observ
 }
 
 static bool displays_arrangement_dirty = true;
+static bool displays_scale_dirty = true;
 static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
 	displays_arrangement_dirty = true;
+	displays_scale_dirty = true;
 }
 
 int OS_OSX::get_current_video_driver() const {
@@ -1525,6 +1539,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
 
 	keyboard_layout_dirty = true;
 	displays_arrangement_dirty = true;
+	displays_scale_dirty = true;
 
 	// Register to be notified on keyboard layout changes
 	CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
@@ -1549,8 +1564,10 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
 		styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (p_desired.resizable ? NSWindowStyleMaskResizable : 0);
 	}
 
+	float displayScale = get_screen_max_scale();
+
 	window_object = [[GodotWindow alloc]
-			initWithContentRect:NSMakeRect(0, 0, p_desired.width, p_desired.height)
+			initWithContentRect:NSMakeRect(0, 0, p_desired.width / displayScale, p_desired.height / displayScale)
 					  styleMask:styleMask
 						backing:NSBackingStoreBuffered
 						  defer:NO];
@@ -1562,17 +1579,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
 		[window_view setWantsLayer:TRUE];
 	}
 
-	float displayScale = 1.0;
-	if (is_hidpi_allowed()) {
-		// note that mainScreen is not screen #0 but the one with the keyboard focus.
-		NSScreen *screen = [NSScreen mainScreen];
-		if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
-			displayScale = fmax(displayScale, [screen backingScaleFactor]);
-		}
-	}
-
-	window_size.width = p_desired.width * displayScale;
-	window_size.height = p_desired.height * displayScale;
+	window_size.width = p_desired.width;
+	window_size.height = p_desired.height;
 
 	if (displayScale > 1.0) {
 		[window_view setWantsBestResolutionOpenGLSurface:YES];
@@ -1660,6 +1668,12 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
 
 	[context makeCurrentContext];
 
+	GLint dim[2];
+	dim[0] = window_size.width;
+	dim[1] = window_size.height;
+	CGLSetParameter((CGLContextObj)[context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]);
+	CGLEnable((CGLContextObj)[context CGLContextObj], kCGLCESurfaceBackingSize);
+
 	set_use_vsync(p_desired.use_vsync);
 
 	[NSApp activateIgnoringOtherApps:YES];
@@ -2074,7 +2088,7 @@ void OS_OSX::warp_mouse_position(const Point2 &p_to) {
 
 		//local point in window coords
 		const NSRect contentRect = [window_view frame];
-		float displayScale = _display_scale();
+		float displayScale = get_screen_max_scale();
 		NSRect pointInWindowRect = NSMakeRect(p_to.x / displayScale, contentRect.size.height - (p_to.y / displayScale) - 1, 0, 0);
 		NSPoint pointOnScreen = [[window_view window] convertRectToScreen:pointInWindowRect].origin;
 
@@ -2094,7 +2108,7 @@ void OS_OSX::warp_mouse_position(const Point2 &p_to) {
 
 void OS_OSX::update_real_mouse_position() {
 
-	get_mouse_pos([window_object mouseLocationOutsideOfEventStream], [window_view backingScaleFactor]);
+	get_mouse_pos([window_object mouseLocationOutsideOfEventStream]);
 	input->set_mouse_position(Point2(mouse_x, mouse_y));
 }
 
@@ -2415,7 +2429,7 @@ Point2 OS_OSX::get_native_screen_position(int p_screen) const {
 
 	NSArray *screenArray = [NSScreen screens];
 	if ((NSUInteger)p_screen < [screenArray count]) {
-		float display_scale = _display_scale([screenArray objectAtIndex:p_screen]);
+		float display_scale = get_screen_max_scale();
 		NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
 		// Return the top-left corner of the screen, for OS X the y starts at the bottom
 		return Point2(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * display_scale;
@@ -2439,13 +2453,9 @@ int OS_OSX::get_screen_dpi(int p_screen) const {
 
 	NSArray *screenArray = [NSScreen screens];
 	if ((NSUInteger)p_screen < [screenArray count]) {
-		float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
 		NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
-		NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
-		CGSize displayPhysicalSize = CGDisplayScreenSize(
-				[[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
-
-		return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale;
+		NSSize displayDPI = [[description objectForKey:NSDeviceResolution] sizeValue];
+		return (displayDPI.width + displayDPI.height) / 2;
 	}
 
 	return 72;
@@ -2458,7 +2468,7 @@ Size2 OS_OSX::get_screen_size(int p_screen) const {
 
 	NSArray *screenArray = [NSScreen screens];
 	if ((NSUInteger)p_screen < [screenArray count]) {
-		float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
+		float displayScale = get_screen_max_scale();
 		// Note: Use frame to get the whole screen size
 		NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
 		return Size2(nsrect.size.width, nsrect.size.height) * displayScale;
@@ -2492,28 +2502,40 @@ void OS_OSX::_update_window() {
 	}
 }
 
-float OS_OSX::_display_scale() const {
-	if (window_object) {
-		return _display_scale([window_object screen]);
-	} else {
-		return _display_scale([NSScreen mainScreen]);
+float OS_OSX::get_screen_scale(int p_screen) const {
+	if (p_screen < 0) {
+		p_screen = get_current_screen();
 	}
-}
 
-float OS_OSX::_display_scale(id screen) const {
 	if (is_hidpi_allowed()) {
-		if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
-			return fmax(1.0, [screen backingScaleFactor]);
+		NSArray *screenArray = [NSScreen screens];
+		if ((NSUInteger)p_screen < [screenArray count]) {
+			if ([[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) {
+				return fmax(1.0, [[screenArray objectAtIndex:p_screen] backingScaleFactor]);
+			}
 		}
 	}
-	return 1.0;
+
+	return 1.f;
+}
+
+float OS_OSX::get_screen_max_scale() const {
+	static float scale = 1.f;
+	if (displays_scale_dirty) {
+		int screen_count = get_screen_count();
+		for (int i = 0; i < screen_count; i++) {
+			scale = fmax(scale, get_screen_scale(i));
+		}
+		displays_scale_dirty = false;
+	}
+	return scale;
 }
 
 Point2 OS_OSX::get_native_window_position() const {
 
 	NSRect nsrect = [window_object frame];
 	Point2 pos;
-	float display_scale = _display_scale();
+	float display_scale = get_screen_max_scale();
 
 	// Return the position of the top-left corner, for OS X the y starts at the bottom
 	pos.x = nsrect.origin.x * display_scale;
@@ -2533,7 +2555,7 @@ Point2 OS_OSX::get_window_position() const {
 void OS_OSX::set_native_window_position(const Point2 &p_position) {
 
 	NSPoint pos;
-	float displayScale = _display_scale();
+	float displayScale = get_screen_max_scale();
 
 	pos.x = p_position.x / displayScale;
 	pos.y = p_position.y / displayScale;
@@ -2561,7 +2583,7 @@ Size2 OS_OSX::get_window_size() const {
 Size2 OS_OSX::get_real_window_size() const {
 
 	NSRect frame = [window_object frame];
-	return Size2(frame.size.width, frame.size.height) * _display_scale();
+	return Size2(frame.size.width, frame.size.height) * get_screen_max_scale();
 }
 
 Size2 OS_OSX::get_max_window_size() const {
@@ -2581,7 +2603,7 @@ void OS_OSX::set_min_window_size(const Size2 p_size) {
 	min_size = p_size;
 
 	if ((min_size != Size2()) && !zoomed) {
-		Size2 size = min_size / _display_scale();
+		Size2 size = min_size / get_screen_max_scale();
 		[window_object setContentMinSize:NSMakeSize(size.x, size.y)];
 	} else {
 		[window_object setContentMinSize:NSMakeSize(0, 0)];
@@ -2597,7 +2619,7 @@ void OS_OSX::set_max_window_size(const Size2 p_size) {
 	max_size = p_size;
 
 	if ((max_size != Size2()) && !zoomed) {
-		Size2 size = max_size / _display_scale();
+		Size2 size = max_size / get_screen_max_scale();
 		[window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
 	} else {
 		[window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
@@ -2606,7 +2628,7 @@ void OS_OSX::set_max_window_size(const Size2 p_size) {
 
 void OS_OSX::set_window_size(const Size2 p_size) {
 
-	Size2 size = p_size / _display_scale();
+	Size2 size = p_size / get_screen_max_scale();
 
 	if (get_borderless_window() == false) {
 		// NSRect used by setFrame includes the title bar, so add it to our size.y
@@ -2638,11 +2660,11 @@ void OS_OSX::set_window_fullscreen(bool p_enabled) {
 			[window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
 		} else {
 			if (min_size != Size2()) {
-				Size2 size = min_size / _display_scale();
+				Size2 size = min_size / get_screen_max_scale();
 				[window_object setContentMinSize:NSMakeSize(size.x, size.y)];
 			}
 			if (max_size != Size2()) {
-				Size2 size = max_size / _display_scale();
+				Size2 size = max_size / get_screen_max_scale();
 				[window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
 			}
 		}
@@ -3202,6 +3224,8 @@ OS_OSX *OS_OSX::singleton = NULL;
 
 OS_OSX::OS_OSX() {
 
+	context = nullptr;
+
 	memset(cursors, 0, sizeof(cursors));
 	key_event_pos = 0;
 	mouse_mode = OS::MOUSE_MODE_VISIBLE;