Browse Source

macOS: Support vsync when embedding OpenGL processes

Closes #106379
Stuart Carnie 5 months ago
parent
commit
aae3370fcd

+ 6 - 0
platform/macos/display_server_embedded.h

@@ -43,9 +43,15 @@ struct DisplayServerEmbeddedState {
 	/// Default to a scale of 2.0, which is the most common.
 	/// Default to a scale of 2.0, which is the most common.
 	float screen_max_scale = 2.0f;
 	float screen_max_scale = 2.0f;
 	float screen_dpi = 96.0f;
 	float screen_dpi = 96.0f;
+	/// The display ID of the window which is displaying the the embedded process content.
+	uint32_t display_id = -1;
 
 
 	void serialize(PackedByteArray &r_data);
 	void serialize(PackedByteArray &r_data);
 	Error deserialize(const PackedByteArray &p_data);
 	Error deserialize(const PackedByteArray &p_data);
+
+	_FORCE_INLINE_ bool operator==(const DisplayServerEmbeddedState &p_other) const {
+		return screen_max_scale == p_other.screen_max_scale && screen_dpi == p_other.screen_dpi && display_id == p_other.display_id;
+	}
 };
 };
 
 
 class DisplayServerEmbedded : public DisplayServer {
 class DisplayServerEmbedded : public DisplayServer {

+ 36 - 3
platform/macos/display_server_embedded.mm

@@ -135,6 +135,7 @@ DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, W
 		if (err != OK) {
 		if (err != OK) {
 			ERR_FAIL_MSG("Could not create OpenGL context.");
 			ERR_FAIL_MSG("Could not create OpenGL context.");
 		}
 		}
+		gl_manager->set_vsync_enabled(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
 	}
 	}
 #endif
 #endif
 
 
@@ -708,15 +709,44 @@ void DisplayServerEmbedded::window_set_ime_position(const Point2i &p_pos, Window
 }
 }
 
 
 void DisplayServerEmbedded::set_state(const DisplayServerEmbeddedState &p_state) {
 void DisplayServerEmbedded::set_state(const DisplayServerEmbeddedState &p_state) {
+	if (state == p_state) {
+		return;
+	}
+
+	uint32_t old_display_id = state.display_id;
+
 	state = p_state;
 	state = p_state;
+
+	if (state.display_id != old_display_id) {
+#if defined(GLES3_ENABLED)
+		if (gl_manager) {
+			gl_manager->set_display_id(state.display_id);
+		}
+#endif
+	}
 }
 }
 
 
 void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
-	// Not supported
+#if defined(GLES3_ENABLED)
+	if (gl_manager) {
+		gl_manager->set_vsync_enabled(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+	}
+#endif
+
+#if defined(RD_ENABLED)
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
+	}
+#endif
 }
 }
 
 
 DisplayServer::VSyncMode DisplayServerEmbedded::window_get_vsync_mode(WindowID p_window) const {
 DisplayServer::VSyncMode DisplayServerEmbedded::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
+#if defined(GLES3_ENABLED)
+	if (gl_manager) {
+		return (gl_manager->is_vsync_enabled() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED);
+	}
+#endif
 #if defined(RD_ENABLED)
 #if defined(RD_ENABLED)
 	if (rendering_context) {
 	if (rendering_context) {
 		return rendering_context->window_get_vsync_mode(p_window);
 		return rendering_context->window_get_vsync_mode(p_window);
@@ -762,14 +792,15 @@ void DisplayServerEmbedded::swap_buffers() {
 }
 }
 
 
 void DisplayServerEmbeddedState::serialize(PackedByteArray &r_data) {
 void DisplayServerEmbeddedState::serialize(PackedByteArray &r_data) {
-	r_data.resize(8);
+	r_data.resize(12);
 
 
 	uint8_t *data = r_data.ptrw();
 	uint8_t *data = r_data.ptrw();
 	data += encode_float(screen_max_scale, data);
 	data += encode_float(screen_max_scale, data);
 	data += encode_float(screen_dpi, data);
 	data += encode_float(screen_dpi, data);
+	data += encode_uint32(display_id, data);
 
 
 	// Assert we had enough space.
 	// Assert we had enough space.
-	DEV_ASSERT(data - r_data.ptrw() >= r_data.size());
+	DEV_ASSERT((data - r_data.ptrw()) >= r_data.size());
 }
 }
 
 
 Error DisplayServerEmbeddedState::deserialize(const PackedByteArray &p_data) {
 Error DisplayServerEmbeddedState::deserialize(const PackedByteArray &p_data) {
@@ -778,6 +809,8 @@ Error DisplayServerEmbeddedState::deserialize(const PackedByteArray &p_data) {
 	screen_max_scale = decode_float(data);
 	screen_max_scale = decode_float(data);
 	data += sizeof(float);
 	data += sizeof(float);
 	screen_dpi = decode_float(data);
 	screen_dpi = decode_float(data);
+	data += sizeof(float);
+	display_id = decode_uint32(data);
 
 
 	return OK;
 	return OK;
 }
 }

+ 10 - 2
platform/macos/display_server_macos.h

@@ -101,6 +101,8 @@ public:
 
 
 		Vector<Vector2> mpath;
 		Vector<Vector2> mpath;
 
 
+		CGDirectDisplayID display_id = -1;
+
 		Point2i mouse_pos;
 		Point2i mouse_pos;
 		WindowResizeEdge edge = WINDOW_EDGE_MAX;
 		WindowResizeEdge edge = WINDOW_EDGE_MAX;
 
 
@@ -253,10 +255,12 @@ private:
 	void initialize_tts() const;
 	void initialize_tts() const;
 
 
 	struct EmbeddedProcessData {
 	struct EmbeddedProcessData {
-		const EmbeddedProcessMacOS *process;
+		EmbeddedProcessMacOS *process;
+		WindowData *wd = nullptr;
 		CALayer *layer_host = nil;
 		CALayer *layer_host = nil;
 	};
 	};
 	HashMap<OS::ProcessID, EmbeddedProcessData> embedded_processes;
 	HashMap<OS::ProcessID, EmbeddedProcessData> embedded_processes;
+	void _window_update_display_id(WindowData *p_wd);
 
 
 public:
 public:
 	void menu_callback(id p_sender);
 	void menu_callback(id p_sender);
@@ -294,6 +298,10 @@ public:
 
 
 	bool is_always_on_top_recursive(WindowID p_window) const;
 	bool is_always_on_top_recursive(WindowID p_window) const;
 
 
+	/**
+	 * Get the display ID of a window.
+	 */
+	uint32_t window_get_display_id(WindowID p_window) const;
 	void window_destroy(WindowID p_window);
 	void window_destroy(WindowID p_window);
 	void window_resize(WindowID p_window, int p_width, int p_height);
 	void window_resize(WindowID p_window, int p_width, int p_height);
 	void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled);
 	void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled);
@@ -461,7 +469,7 @@ public:
 
 
 	virtual void enable_for_stealing_focus(OS::ProcessID pid) override;
 	virtual void enable_for_stealing_focus(OS::ProcessID pid) override;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-	Error embed_process_update(WindowID p_window, const EmbeddedProcessMacOS *p_process);
+	Error embed_process_update(WindowID p_window, EmbeddedProcessMacOS *p_process);
 #endif
 #endif
 	virtual Error request_close_embedded_process(OS::ProcessID p_pid) override;
 	virtual Error request_close_embedded_process(OS::ProcessID p_pid) override;
 	virtual Error remove_embedded_process(OS::ProcessID p_pid) override;
 	virtual Error remove_embedded_process(OS::ProcessID p_pid) override;

+ 31 - 2
platform/macos/display_server_macos.mm

@@ -54,6 +54,7 @@
 #include "scene/resources/image_texture.h"
 #include "scene/resources/image_texture.h"
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
+#import "display_server_embedded.h"
 #import "editor/embedded_process_macos.h"
 #import "editor/embedded_process_macos.h"
 #endif
 #endif
 
 
@@ -87,7 +88,7 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 	{
 	{
 		WindowData &wd = windows[id];
 		WindowData &wd = windows[id];
 
 
-		wd.window_delegate = [[GodotWindowDelegate alloc] init];
+		wd.window_delegate = [[GodotWindowDelegate alloc] initWithDisplayServer:this];
 		ERR_FAIL_NULL_V_MSG(wd.window_delegate, INVALID_WINDOW_ID, "Can't create a window delegate");
 		ERR_FAIL_NULL_V_MSG(wd.window_delegate, INVALID_WINDOW_ID, "Can't create a window delegate");
 		[wd.window_delegate setWindowID:id];
 		[wd.window_delegate setWindowID:id];
 
 
@@ -2196,6 +2197,8 @@ void DisplayServerMacOS::reparent_check(WindowID p_window) {
 	WindowData &wd = windows[p_window];
 	WindowData &wd = windows[p_window];
 	NSScreen *screen = [wd.window_object screen];
 	NSScreen *screen = [wd.window_object screen];
 
 
+	_window_update_display_id(&wd);
+
 	if (wd.transient_parent != INVALID_WINDOW_ID) {
 	if (wd.transient_parent != INVALID_WINDOW_ID) {
 		WindowData &wd_parent = windows[wd.transient_parent];
 		WindowData &wd_parent = windows[wd.transient_parent];
 		NSScreen *parent_screen = [wd_parent.window_object screen];
 		NSScreen *parent_screen = [wd_parent.window_object screen];
@@ -3284,9 +3287,34 @@ void DisplayServerMacOS::enable_for_stealing_focus(OS::ProcessID pid) {
 		ERR_FAIL_V(m_retval);                        \
 		ERR_FAIL_V(m_retval);                        \
 	}
 	}
 
 
+uint32_t DisplayServerMacOS::window_get_display_id(WindowID p_window) const {
+	const WindowData *wd;
+	GET_OR_FAIL_V(wd, windows, p_window, -1);
+	return wd->display_id;
+}
+
+void DisplayServerMacOS::_window_update_display_id(WindowData *p_wd) {
+	NSScreen *screen = [p_wd->window_object screen];
+	CGDirectDisplayID display_id = [[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
+	if (p_wd->display_id == display_id) {
+		return;
+	}
+
+	p_wd->display_id = display_id;
+
+#ifdef TOOLS_ENABLED
+	// Notify any embedded processes of the new display ID, so that they can potentially update their vsync.
+	for (KeyValue<OS::ProcessID, EmbeddedProcessData> &E : embedded_processes) {
+		if (E.value.wd == p_wd) {
+			E.value.process->display_state_changed();
+		}
+	}
+#endif
+}
+
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 
 
-Error DisplayServerMacOS::embed_process_update(WindowID p_window, const EmbeddedProcessMacOS *p_process) {
+Error DisplayServerMacOS::embed_process_update(WindowID p_window, EmbeddedProcessMacOS *p_process) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	WindowData *wd;
 	WindowData *wd;
@@ -3303,6 +3331,7 @@ Error DisplayServerMacOS::embed_process_update(WindowID p_window, const Embedded
 		ed = &embedded_processes.insert(p_pid, EmbeddedProcessData())->value;
 		ed = &embedded_processes.insert(p_pid, EmbeddedProcessData())->value;
 
 
 		ed->process = p_process;
 		ed->process = p_process;
+		ed->wd = wd;
 
 
 		CALayerHost *host = [CALayerHost new];
 		CALayerHost *host = [CALayerHost new];
 		uint32_t p_context_id = p_process->get_context_id();
 		uint32_t p_context_id = p_process->get_context_id();

+ 3 - 1
platform/macos/editor/embedded_process_macos.h

@@ -79,7 +79,7 @@ class EmbeddedProcessMacOS final : public EmbeddedProcessBase {
 	// Helper functions.
 	// Helper functions.
 
 
 	void _try_embed_process();
 	void _try_embed_process();
-	void update_embedded_process() const;
+	void update_embedded_process();
 	void _joy_connection_changed(int p_index, bool p_connected) const;
 	void _joy_connection_changed(int p_index, bool p_connected) const;
 
 
 protected:
 protected:
@@ -113,6 +113,8 @@ public:
 
 
 	_FORCE_INLINE_ LayerHost *get_layer_host() const { return layer_host; }
 	_FORCE_INLINE_ LayerHost *get_layer_host() const { return layer_host; }
 
 
+	void display_state_changed();
+
 	// MARK: - Embedded process state
 	// MARK: - Embedded process state
 	_FORCE_INLINE_ DisplayServer::MouseMode get_mouse_mode() const { return mouse_mode; }
 	_FORCE_INLINE_ DisplayServer::MouseMode get_mouse_mode() const { return mouse_mode; }
 
 

+ 15 - 11
platform/macos/editor/embedded_process_macos.mm

@@ -53,7 +53,7 @@ void EmbeddedProcessMacOS::_notification(int p_what) {
 	}
 	}
 }
 }
 
 
-void EmbeddedProcessMacOS::update_embedded_process() const {
+void EmbeddedProcessMacOS::update_embedded_process() {
 	layer_host->set_rect(get_adjusted_embedded_window_rect(get_rect()));
 	layer_host->set_rect(get_adjusted_embedded_window_rect(get_rect()));
 	if (is_embedding_completed()) {
 	if (is_embedding_completed()) {
 		ds->embed_process_update(window->get_window_id(), this);
 		ds->embed_process_update(window->get_window_id(), this);
@@ -130,24 +130,28 @@ void EmbeddedProcessMacOS::request_close() {
 	}
 	}
 }
 }
 
 
+void EmbeddedProcessMacOS::display_state_changed() {
+	DisplayServerEmbeddedState state;
+	state.screen_max_scale = ds->screen_get_max_scale();
+	state.screen_dpi = ds->screen_get_dpi();
+	state.display_id = ds->window_get_display_id(window->get_window_id());
+	PackedByteArray data;
+	state.serialize(data);
+	script_debugger->send_message("embed:ds_state", { data });
+}
+
 void EmbeddedProcessMacOS::_try_embed_process() {
 void EmbeddedProcessMacOS::_try_embed_process() {
 	if (current_process_id == 0 || script_debugger == nullptr || context_id == 0) {
 	if (current_process_id == 0 || script_debugger == nullptr || context_id == 0) {
 		return;
 		return;
 	}
 	}
 
 
-	Error err = ds->embed_process_update(window->get_window_id(), this);
+	DisplayServer::WindowID wid = window->get_window_id();
+	Error err = ds->embed_process_update(wid, this);
 	if (err == OK) {
 	if (err == OK) {
 		layer_host->set_rect(get_adjusted_embedded_window_rect(get_rect()));
 		layer_host->set_rect(get_adjusted_embedded_window_rect(get_rect()));
 
 
-		// Replicate some of the DisplayServer state.
-		{
-			DisplayServerEmbeddedState state;
-			state.screen_max_scale = ds->screen_get_max_scale();
-			state.screen_dpi = ds->screen_get_dpi();
-			PackedByteArray data;
-			state.serialize(data);
-			script_debugger->send_message("embed:ds_state", { data });
-		}
+		// Replicate important DisplayServer state.
+		display_state_changed();
 
 
 		Rect2i rect = get_screen_embedded_window_rect();
 		Rect2i rect = get_screen_embedded_window_rect();
 		script_debugger->send_message("embed:window_size", { rect.size });
 		script_debugger->send_message("embed:window_size", { rect.size });

+ 16 - 0
platform/macos/embedded_gl_manager.h

@@ -53,6 +53,9 @@ class GLManagerEmbedded {
 	/// Triple-buffering is used to avoid stuttering.
 	/// Triple-buffering is used to avoid stuttering.
 	static constexpr uint32_t BUFFER_COUNT = 3;
 	static constexpr uint32_t BUFFER_COUNT = 3;
 
 
+	// The display ID for which vsync is used. If this value is -1, vsync is disabled.
+	constexpr static uint32_t INVALID_DISPLAY_ID = static_cast<uint32_t>(-1);
+
 	struct FrameBuffer {
 	struct FrameBuffer {
 		IOSurfaceRef surface = nullptr;
 		IOSurfaceRef surface = nullptr;
 		unsigned int tex = 0;
 		unsigned int tex = 0;
@@ -86,12 +89,25 @@ class GLManagerEmbedded {
 	CGLTexImageIOSurface2DPtr CGLTexImageIOSurface2D = nullptr;
 	CGLTexImageIOSurface2DPtr CGLTexImageIOSurface2D = nullptr;
 	CGLErrorStringPtr CGLErrorString = nullptr;
 	CGLErrorStringPtr CGLErrorString = nullptr;
 
 
+	uint32_t display_id = INVALID_DISPLAY_ID;
+	CVDisplayLinkRef display_link;
+	bool vsync_enabled = false;
+	bool display_link_running = false;
+	dispatch_semaphore_t display_semaphore = nullptr;
+
+	void create_display_link();
+	void release_display_link();
+
 public:
 public:
 	Error window_create(DisplayServer::WindowID p_window_id, CALayer *p_layer, int p_width, int p_height);
 	Error window_create(DisplayServer::WindowID p_window_id, CALayer *p_layer, int p_width, int p_height);
 	void window_destroy(DisplayServer::WindowID p_window_id);
 	void window_destroy(DisplayServer::WindowID p_window_id);
 	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
 	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
 	Size2i window_get_size(DisplayServer::WindowID p_window_id) const;
 	Size2i window_get_size(DisplayServer::WindowID p_window_id) const;
 
 
+	void set_display_id(uint32_t p_display_id);
+	void set_vsync_enabled(bool p_enabled);
+	bool is_vsync_enabled() const { return vsync_enabled; }
+
 	void release_current();
 	void release_current();
 	void swap_buffers();
 	void swap_buffers();
 
 

+ 63 - 0
platform/macos/embedded_gl_manager.mm

@@ -237,6 +237,10 @@ void GLManagerEmbedded::swap_buffers() {
 	}
 	}
 	last_valid = true;
 	last_valid = true;
 
 
+	if (display_link_running) {
+		dispatch_semaphore_wait(display_semaphore, DISPATCH_TIME_FOREVER);
+	}
+
 	[CATransaction begin];
 	[CATransaction begin];
 	[CATransaction setDisableActions:YES];
 	[CATransaction setDisableActions:YES];
 	win.layer.contents = (__bridge id)win.framebuffers[win.current_fb].surface;
 	win.layer.contents = (__bridge id)win.framebuffers[win.current_fb].surface;
@@ -249,7 +253,65 @@ Error GLManagerEmbedded::initialize() {
 	return framework_loaded ? OK : ERR_CANT_CREATE;
 	return framework_loaded ? OK : ERR_CANT_CREATE;
 }
 }
 
 
+void GLManagerEmbedded::create_display_link() {
+	DEV_ASSERT(display_link == nullptr);
+
+	CVReturn err = CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &display_link);
+	ERR_FAIL_COND_MSG(err != kCVReturnSuccess, "Failed to create display link.");
+
+	__block dispatch_semaphore_t local_semaphore = display_semaphore;
+
+	CVDisplayLinkSetOutputHandler(display_link, ^CVReturn(CVDisplayLinkRef p_display_link, const CVTimeStamp *p_now, const CVTimeStamp *p_output_time, CVOptionFlags p_flags, CVOptionFlags *p_flags_out) {
+		dispatch_semaphore_signal(local_semaphore);
+		return kCVReturnSuccess;
+	});
+}
+
+void GLManagerEmbedded::release_display_link() {
+	DEV_ASSERT(display_link != nullptr);
+	if (CVDisplayLinkIsRunning(display_link)) {
+		CVDisplayLinkStop(display_link);
+	}
+	CVDisplayLinkRelease(display_link);
+	display_link = nullptr;
+}
+
+void GLManagerEmbedded::set_display_id(uint32_t p_display_id) {
+	if (display_id == p_display_id) {
+		return;
+	}
+
+	CVReturn err = CVDisplayLinkSetCurrentCGDisplay(display_link, static_cast<CGDirectDisplayID>(p_display_id));
+	ERR_FAIL_COND_MSG(err != kCVReturnSuccess, "Failed to set display ID for display link.");
+}
+
+void GLManagerEmbedded::set_vsync_enabled(bool p_enabled) {
+	if (p_enabled == vsync_enabled) {
+		return;
+	}
+
+	vsync_enabled = p_enabled;
+
+	if (vsync_enabled) {
+		if (!CVDisplayLinkIsRunning(display_link)) {
+			CVReturn err = CVDisplayLinkStart(display_link);
+			ERR_FAIL_COND_MSG(err != kCVReturnSuccess, "Failed to start display link.");
+			display_link_running = true;
+		}
+	} else {
+		if (CVDisplayLinkIsRunning(display_link)) {
+			CVReturn err = CVDisplayLinkStop(display_link);
+			ERR_FAIL_COND_MSG(err != kCVReturnSuccess, "Failed to stop display link.");
+			display_link_running = false;
+		}
+	}
+}
+
 GLManagerEmbedded::GLManagerEmbedded() {
 GLManagerEmbedded::GLManagerEmbedded() {
+	display_semaphore = dispatch_semaphore_create(BUFFER_COUNT);
+
+	create_display_link();
+
 	NSBundle *framework = [NSBundle bundleWithIdentifier:@"com.apple.opengl"];
 	NSBundle *framework = [NSBundle bundleWithIdentifier:@"com.apple.opengl"];
 	if ([framework load]) {
 	if ([framework load]) {
 		void *library_handle = dlopen([framework.executablePath UTF8String], RTLD_NOW);
 		void *library_handle = dlopen([framework.executablePath UTF8String], RTLD_NOW);
@@ -263,6 +325,7 @@ GLManagerEmbedded::GLManagerEmbedded() {
 }
 }
 
 
 GLManagerEmbedded::~GLManagerEmbedded() {
 GLManagerEmbedded::~GLManagerEmbedded() {
+	release_display_link();
 	release_current();
 	release_current();
 }
 }
 
 

+ 5 - 3
platform/macos/godot_window_delegate.h

@@ -35,10 +35,12 @@
 #import <AppKit/AppKit.h>
 #import <AppKit/AppKit.h>
 #import <Foundation/Foundation.h>
 #import <Foundation/Foundation.h>
 
 
-@interface GodotWindowDelegate : NSObject <NSWindowDelegate> {
-	DisplayServer::WindowID window_id;
-}
+class DisplayServerMacOS;
+
+@interface GodotWindowDelegate : NSObject <NSWindowDelegate>
 
 
 - (void)setWindowID:(DisplayServer::WindowID)wid;
 - (void)setWindowID:(DisplayServer::WindowID)wid;
 
 
+- (instancetype)initWithDisplayServer:(DisplayServerMacOS *)p_ds;
+
 @end
 @end

+ 31 - 41
platform/macos/godot_window_delegate.mm

@@ -35,15 +35,25 @@
 #import "godot_content_view.h"
 #import "godot_content_view.h"
 #import "godot_window.h"
 #import "godot_window.h"
 
 
-@implementation GodotWindowDelegate
+@implementation GodotWindowDelegate {
+	DisplayServer::WindowID window_id;
+	DisplayServerMacOS *ds;
+}
+
+- (instancetype)initWithDisplayServer:(DisplayServerMacOS *)p_ds {
+	if (self = [super init]) {
+		ds = p_ds;
+		window_id = DisplayServerMacOS::INVALID_WINDOW_ID;
+	}
+	return self;
+}
 
 
 - (void)setWindowID:(DisplayServer::WindowID)wid {
 - (void)setWindowID:(DisplayServer::WindowID)wid {
 	window_id = wid;
 	window_id = wid;
 }
 }
 
 
 - (BOOL)windowShouldClose:(id)sender {
 - (BOOL)windowShouldClose:(id)sender {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return YES;
 		return YES;
 	}
 	}
 
 
@@ -52,8 +62,7 @@
 }
 }
 
 
 - (void)windowWillClose:(NSNotification *)notification {
 - (void)windowWillClose:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -73,8 +82,7 @@
 }
 }
 
 
 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -91,8 +99,7 @@
 }
 }
 
 
 - (void)windowDidFailToEnterFullScreen:(NSWindow *)window {
 - (void)windowDidFailToEnterFullScreen:(NSWindow *)window {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -101,8 +108,7 @@
 }
 }
 
 
 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -126,8 +132,7 @@
 }
 }
 
 
 - (void)windowWillExitFullScreen:(NSNotification *)notification {
 - (void)windowWillExitFullScreen:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -143,8 +148,7 @@
 }
 }
 
 
 - (void)windowDidFailToExitFullScreen:(NSWindow *)window {
 - (void)windowDidFailToExitFullScreen:(NSWindow *)window {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -159,8 +163,7 @@
 }
 }
 
 
 - (void)windowDidExitFullScreen:(NSNotification *)notification {
 - (void)windowDidExitFullScreen:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -206,8 +209,7 @@
 }
 }
 
 
 - (void)windowDidChangeBackingProperties:(NSNotification *)notification {
 - (void)windowDidChangeBackingProperties:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -237,8 +239,7 @@
 }
 }
 
 
 - (void)windowWillStartLiveResize:(NSNotification *)notification {
 - (void)windowWillStartLiveResize:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (ds && ds->has_window(window_id)) {
+	if (ds->has_window(window_id)) {
 		DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
 		DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
 		wd.last_frame_rect = [wd.window_object frame];
 		wd.last_frame_rect = [wd.window_object frame];
 		ds->set_is_resizing(true);
 		ds->set_is_resizing(true);
@@ -246,15 +247,11 @@
 }
 }
 
 
 - (void)windowDidEndLiveResize:(NSNotification *)notification {
 - (void)windowDidEndLiveResize:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (ds) {
-		ds->set_is_resizing(false);
-	}
+	ds->set_is_resizing(false);
 }
 }
 
 
 - (void)windowDidResize:(NSNotification *)notification {
 - (void)windowDidResize:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -277,8 +274,7 @@
 }
 }
 
 
 - (void)windowDidChangeScreen:(NSNotification *)notification {
 - (void)windowDidChangeScreen:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -286,8 +282,7 @@
 }
 }
 
 
 - (void)windowDidMove:(NSNotification *)notification {
 - (void)windowDidMove:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -300,8 +295,7 @@
 }
 }
 
 
 - (void)windowDidBecomeKey:(NSNotification *)notification {
 - (void)windowDidBecomeKey:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -332,8 +326,7 @@
 }
 }
 
 
 - (void)windowDidResignKey:(NSNotification *)notification {
 - (void)windowDidResignKey:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -352,8 +345,7 @@
 }
 }
 
 
 - (void)windowDidMiniaturize:(NSNotification *)notification {
 - (void)windowDidMiniaturize:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -368,8 +360,7 @@
 }
 }
 
 
 - (void)windowDidDeminiaturize:(NSNotification *)notification {
 - (void)windowDidDeminiaturize:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 
 
@@ -386,8 +377,7 @@
 }
 }
 
 
 - (void)windowDidChangeOcclusionState:(NSNotification *)notification {
 - (void)windowDidChangeOcclusionState:(NSNotification *)notification {
-	DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
-	if (!ds || !ds->has_window(window_id)) {
+	if (!ds->has_window(window_id)) {
 		return;
 		return;
 	}
 	}
 	DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
 	DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);