Browse Source

Merge pull request #48622 from Geometror/reimplement-disableable-vsync

Hugo Locurcio 4 years ago
parent
commit
a2d5f191d8
41 changed files with 310 additions and 257 deletions
  1. 1 0
      core/config/project_settings.cpp
  2. 0 2
      core/os/os.h
  3. 39 30
      doc/classes/DisplayServer.xml
  4. 5 7
      doc/classes/ProjectSettings.xml
  5. 46 10
      drivers/vulkan/vulkan_context.cpp
  6. 5 1
      drivers/vulkan/vulkan_context.h
  7. 19 27
      main/main.cpp
  8. 0 6
      misc/dist/linux/godot.6
  9. 0 2
      misc/dist/shell/_godot.zsh-completion
  10. 0 2
      misc/dist/shell/godot.bash-completion
  11. 0 2
      misc/dist/shell/godot.fish
  12. 20 5
      platform/android/display_server_android.cpp
  13. 4 2
      platform/android/display_server_android.h
  14. 2 2
      platform/android/vulkan/vulkan_context_android.cpp
  15. 1 1
      platform/android/vulkan/vulkan_context_android.h
  16. 5 2
      platform/iphone/display_server_iphone.h
  17. 20 4
      platform/iphone/display_server_iphone.mm
  18. 1 1
      platform/iphone/vulkan_context_iphone.h
  19. 2 2
      platform/iphone/vulkan_context_iphone.mm
  20. 24 8
      platform/linuxbsd/display_server_x11.cpp
  21. 7 4
      platform/linuxbsd/display_server_x11.h
  22. 2 2
      platform/linuxbsd/vulkan_context_x11.cpp
  23. 1 1
      platform/linuxbsd/vulkan_context_x11.h
  24. 7 4
      platform/osx/display_server_osx.h
  25. 24 8
      platform/osx/display_server_osx.mm
  26. 1 1
      platform/osx/vulkan_context_osx.h
  27. 2 2
      platform/osx/vulkan_context_osx.mm
  28. 1 35
      platform/windows/context_gl_windows.cpp
  29. 0 3
      platform/windows/context_gl_windows.h
  30. 20 12
      platform/windows/display_server_windows.cpp
  31. 7 7
      platform/windows/display_server_windows.h
  32. 2 3
      platform/windows/vulkan_context_win.cpp
  33. 1 1
      platform/windows/vulkan_context_win.h
  34. 2 1
      scene/main/window.cpp
  35. 17 32
      servers/display_server.cpp
  36. 14 17
      servers/display_server.h
  37. 1 1
      servers/display_server_headless.h
  38. 3 3
      servers/rendering/renderer_viewport.cpp
  39. 2 2
      servers/rendering/renderer_viewport.h
  40. 1 1
      servers/rendering/rendering_server_default.h
  41. 1 1
      servers/rendering_server.h

+ 1 - 0
core/config/project_settings.cpp

@@ -1114,6 +1114,7 @@ ProjectSettings::ProjectSettings() {
 
 
 	// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
 	// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
 	custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor");
 	custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor");
+	custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::STRING, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox");
 	custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
 	custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
 	GLOBAL_DEF("physics/2d/run_on_thread", false);
 	GLOBAL_DEF("physics/2d/run_on_thread", false);
 	GLOBAL_DEF("physics/3d/run_on_thread", false);
 	GLOBAL_DEF("physics/3d/run_on_thread", false);

+ 0 - 2
core/os/os.h

@@ -58,8 +58,6 @@ class OS {
 	int _orientation;
 	int _orientation;
 	bool _allow_hidpi = false;
 	bool _allow_hidpi = false;
 	bool _allow_layered = false;
 	bool _allow_layered = false;
-	bool _use_vsync;
-	bool _vsync_via_compositor;
 	bool _stdout_enabled = true;
 	bool _stdout_enabled = true;
 	bool _stderr_enabled = true;
 	bool _stderr_enabled = true;
 
 

+ 39 - 30
doc/classes/DisplayServer.xml

@@ -44,9 +44,11 @@
 			</return>
 			</return>
 			<argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode">
 			<argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode">
 			</argument>
 			</argument>
-			<argument index="1" name="flags" type="int">
+			<argument index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode">
 			</argument>
 			</argument>
-			<argument index="2" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)">
+			<argument index="2" name="flags" type="int">
+			</argument>
+			<argument index="3" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)">
 			</argument>
 			</argument>
 			<description>
 			<description>
 			</description>
 			</description>
@@ -671,34 +673,6 @@
 				[b]Note:[/b] This method is implemented on Android, iOS and UWP.
 				[b]Note:[/b] This method is implemented on Android, iOS and UWP.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="vsync_is_enabled" qualifiers="const">
-			<return type="bool">
-			</return>
-			<description>
-			</description>
-		</method>
-		<method name="vsync_is_using_via_compositor" qualifiers="const">
-			<return type="bool">
-			</return>
-			<description>
-			</description>
-		</method>
-		<method name="vsync_set_enabled">
-			<return type="void">
-			</return>
-			<argument index="0" name="enabled" type="bool">
-			</argument>
-			<description>
-			</description>
-		</method>
-		<method name="vsync_set_use_via_compositor">
-			<return type="void">
-			</return>
-			<argument index="0" name="enabled" type="bool">
-			</argument>
-			<description>
-			</description>
-		</method>
 		<method name="window_attach_instance_id">
 		<method name="window_attach_instance_id">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
@@ -791,6 +765,15 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="window_get_vsync_mode" qualifiers="const">
+			<return type="int" enum="DisplayServer.VSyncMode">
+			</return>
+			<argument index="0" name="window_id" type="int" default="0">
+			</argument>
+			<description>
+				Returns the VSync mode of the given window.
+			</description>
+		</method>
 		<method name="window_move_to_foreground">
 		<method name="window_move_to_foreground">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
@@ -995,6 +978,19 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="window_set_vsync_mode">
+			<return type="void">
+			</return>
+			<argument index="0" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode">
+			</argument>
+			<argument index="1" name="window_id" type="int" default="0">
+			</argument>
+			<description>
+				Sets the VSync mode of the given window.
+				See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
+				Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported.
+			</description>
+		</method>
 		<method name="window_set_window_event_callback">
 		<method name="window_set_window_event_callback">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
@@ -1151,5 +1147,18 @@
 		</constant>
 		</constant>
 		<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
 		<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
 		</constant>
 		</constant>
+		<constant name="VSYNC_DISABLED" value="0" enum="VSyncMode">
+			No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible).
+		</constant>
+		<constant name="VSYNC_ENABLED" value="1" enum="VSyncMode">
+			Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible).
+		</constant>
+		<constant name="VSYNC_ADAPTIVE" value="2" enum="VSyncMode">
+			Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible), otherwise vertical synchronization is enabled to avoid tearing.
+		</constant>
+		<constant name="VSYNC_MAILBOX" value="3" enum="VSyncMode">
+			Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible).
+			Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag.
+		</constant>
 	</constants>
 	</constants>
 </class>
 </class>

+ 5 - 7
doc/classes/ProjectSettings.xml

@@ -445,7 +445,7 @@
 		</member>
 		</member>
 		<member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0">
 		<member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0">
 			Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging.
 			Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging.
-			If [member display/window/vsync/use_vsync] is enabled, it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
+			If [member display/window/vsync/vsync_mode] is set to [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
 			This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions.
 			This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions.
 		</member>
 		</member>
 		<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
 		<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
@@ -532,12 +532,10 @@
 		<member name="display/window/size/width" type="int" setter="" getter="" default="1024">
 		<member name="display/window/size/width" type="int" setter="" getter="" default="1024">
 			Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
 			Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
 		</member>
 		</member>
-		<member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true">
-			If [code]true[/code], enables vertical synchronization. This eliminates tearing that may appear in moving scenes, at the cost of higher input latency and stuttering at lower framerates. If [code]false[/code], vertical synchronization will be disabled, however, many platforms will enforce it regardless (such as mobile platforms and HTML5).
-		</member>
-		<member name="display/window/vsync/vsync_via_compositor" type="bool" setter="" getter="" default="false">
-			If [code]Use Vsync[/code] is enabled and this setting is [code]true[/code], enables vertical synchronization via the operating system's window compositor when in windowed mode and the compositor is enabled. This will prevent stutter in certain situations. (Windows only.)
-			[b]Note:[/b] This option is experimental and meant to alleviate stutter experienced by some users. However, some users have experienced a Vsync framerate halving (e.g. from 60 FPS to 30 FPS) when using it.
+		<member name="display/window/vsync/vsync_mode" type="String" setter="" getter="" default="&quot;Enabled&quot;">
+			Sets the VSync mode for the main game window.
+			See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
+			Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported.
 		</member>
 		</member>
 		<member name="editor/node_naming/name_casing" type="int" setter="" getter="" default="0">
 		<member name="editor/node_naming/name_casing" type="int" setter="" getter="" default="0">
 			When creating node names automatically, set the type of casing in this project. This is mostly an editor setting.
 			When creating node names automatically, set the type of casing in this project. This is mostly an editor setting.

+ 46 - 10
drivers/vulkan/vulkan_context.cpp

@@ -1189,7 +1189,7 @@ bool VulkanContext::_use_validation_layers() {
 	return Engine::get_singleton()->is_validation_layers_enabled();
 	return Engine::get_singleton()->is_validation_layers_enabled();
 }
 }
 
 
-Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) {
+Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) {
 	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
 	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
 
 
 	if (!queues_initialized) {
 	if (!queues_initialized) {
@@ -1217,6 +1217,7 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfa
 	window.surface = p_surface;
 	window.surface = p_surface;
 	window.width = p_width;
 	window.width = p_width;
 	window.height = p_height;
 	window.height = p_height;
+	window.vsync_mode = p_vsync_mode;
 	Error err = _update_swap_chain(&window);
 	Error err = _update_swap_chain(&window);
 	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
 	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
 
 
@@ -1360,7 +1361,6 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 	}
 	}
 	// The FIFO present mode is guaranteed by the spec to be supported
 	// The FIFO present mode is guaranteed by the spec to be supported
 	// and to have no tearing.  It's a great default present mode to use.
 	// and to have no tearing.  It's a great default present mode to use.
-	VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
 
 
 	//  There are times when you may wish to use another present mode.  The
 	//  There are times when you may wish to use another present mode.  The
 	//  following code shows how to select them, and the comments provide some
 	//  following code shows how to select them, and the comments provide some
@@ -1389,16 +1389,41 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 	// the application wants the late image to be immediately displayed, even
 	// the application wants the late image to be immediately displayed, even
 	// though that may mean some tearing.
 	// though that may mean some tearing.
 
 
-	if (window->presentMode != swapchainPresentMode) {
-		for (size_t i = 0; i < presentModeCount; ++i) {
-			if (presentModes[i] == window->presentMode) {
-				swapchainPresentMode = window->presentMode;
-				break;
-			}
+	VkPresentModeKHR requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
+	switch (window->vsync_mode) {
+		case DisplayServer::VSYNC_MAILBOX:
+			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR;
+			break;
+		case DisplayServer::VSYNC_ADAPTIVE:
+			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR;
+			break;
+		case DisplayServer::VSYNC_ENABLED:
+			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
+			break;
+		case DisplayServer::VSYNC_DISABLED:
+			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR;
+			break;
+	}
+
+	// Check if the requested mode is available.
+	bool present_mode_available = false;
+	for (uint32_t i = 0; i < presentModeCount; i++) {
+		if (presentModes[i] == requested_present_mode) {
+			present_mode_available = true;
 		}
 		}
 	}
 	}
+
+	// Set the windows present mode if it is available, otherwise FIFO is used (guaranteed supported).
+	if (present_mode_available) {
+		window->presentMode = requested_present_mode;
+	} else {
+		WARN_PRINT("Requested VSync mode is not available!");
+		window->vsync_mode = DisplayServer::VSYNC_ENABLED; //Set to default
+	}
+
+	print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode)));
+
 	free(presentModes);
 	free(presentModes);
-	ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n");
 
 
 	// Determine the number of VkImages to use in the swap chain.
 	// Determine the number of VkImages to use in the swap chain.
 	// Application desires to acquire 3 images at a time for triple
 	// Application desires to acquire 3 images at a time for triple
@@ -1455,7 +1480,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 		/*pQueueFamilyIndices*/ nullptr,
 		/*pQueueFamilyIndices*/ nullptr,
 		/*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
 		/*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
 		/*compositeAlpha*/ compositeAlpha,
 		/*compositeAlpha*/ compositeAlpha,
-		/*presentMode*/ swapchainPresentMode,
+		/*presentMode*/ window->presentMode,
 		/*clipped*/ true,
 		/*clipped*/ true,
 		/*oldSwapchain*/ VK_NULL_HANDLE,
 		/*oldSwapchain*/ VK_NULL_HANDLE,
 	};
 	};
@@ -2162,6 +2187,17 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
 	return pipeline_cache_id;
 	return pipeline_cache_id;
 }
 }
 
 
+DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const {
+	ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+	return windows[p_window].vsync_mode;
+}
+
+void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
+	ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+	windows[p_window].vsync_mode = p_mode;
+	_update_swap_chain(&windows[p_window]);
+}
+
 VulkanContext::VulkanContext() {
 VulkanContext::VulkanContext() {
 	command_buffer_queue.resize(1); // First one is always the setup command.
 	command_buffer_queue.resize(1); // First one is always the setup command.
 	command_buffer_queue.write[0] = nullptr;
 	command_buffer_queue.write[0] = nullptr;

+ 5 - 1
drivers/vulkan/vulkan_context.h

@@ -124,6 +124,7 @@ private:
 		uint32_t current_buffer = 0;
 		uint32_t current_buffer = 0;
 		int width = 0;
 		int width = 0;
 		int height = 0;
 		int height = 0;
+		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
 		VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
 		VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
 		VkRenderPass render_pass = VK_NULL_HANDLE;
 		VkRenderPass render_pass = VK_NULL_HANDLE;
 	};
 	};
@@ -222,7 +223,7 @@ private:
 protected:
 protected:
 	virtual const char *_get_platform_surface_extension() const = 0;
 	virtual const char *_get_platform_surface_extension() const = 0;
 
 
-	virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height);
+	virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height);
 
 
 	virtual bool _use_validation_layers();
 	virtual bool _use_validation_layers();
 
 
@@ -276,6 +277,9 @@ public:
 	String get_device_name() const;
 	String get_device_name() const;
 	String get_device_pipeline_cache_uuid() const;
 	String get_device_pipeline_cache_uuid() const;
 
 
+	void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
+	DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const;
+
 	VulkanContext();
 	VulkanContext();
 	virtual ~VulkanContext();
 	virtual ~VulkanContext();
 };
 };

+ 19 - 27
main/main.cpp

@@ -151,9 +151,9 @@ static bool auto_build_solutions = false;
 
 
 static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
 static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
 static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
 static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
+static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED;
 static uint32_t window_flags = 0;
 static uint32_t window_flags = 0;
 static Size2i window_size = Size2i(1024, 600);
 static Size2i window_size = Size2i(1024, 600);
-static bool window_vsync_via_compositor = false;
 
 
 static int init_screen = -1;
 static int init_screen = -1;
 static bool init_fullscreen = false;
 static bool init_fullscreen = false;
@@ -338,8 +338,6 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("  --position <X>,<Y>                           Request window position.\n");
 	OS::get_singleton()->print("  --position <X>,<Y>                           Request window position.\n");
 	OS::get_singleton()->print("  --low-dpi                                    Force low-DPI mode (macOS and Windows only).\n");
 	OS::get_singleton()->print("  --low-dpi                                    Force low-DPI mode (macOS and Windows only).\n");
 	OS::get_singleton()->print("  --no-window                                  Disable window creation (Windows only). Useful together with --script.\n");
 	OS::get_singleton()->print("  --no-window                                  Disable window creation (Windows only). Useful together with --script.\n");
-	OS::get_singleton()->print("  --enable-vsync-via-compositor                When vsync is enabled, vsync via the OS' window compositor (Windows only).\n");
-	OS::get_singleton()->print("  --disable-vsync-via-compositor               Disable vsync via the OS' window compositor (Windows only).\n");
 	OS::get_singleton()->print("  --single-window                              Use a single window (no separate subwindows).\n");
 	OS::get_singleton()->print("  --single-window                              Use a single window (no separate subwindows).\n");
 	OS::get_singleton()->print("  --tablet-driver                              Pen tablet input driver.\n");
 	OS::get_singleton()->print("  --tablet-driver                              Pen tablet input driver.\n");
 	OS::get_singleton()->print("\n");
 	OS::get_singleton()->print("\n");
@@ -599,11 +597,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	Vector<String> breakpoints;
 	Vector<String> breakpoints;
 	bool use_custom_res = true;
 	bool use_custom_res = true;
 	bool force_res = false;
 	bool force_res = false;
-	bool saw_vsync_via_compositor_override = false;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	bool found_project = false;
 	bool found_project = false;
 #endif
 #endif
-	bool use_vsync = false;
 
 
 	packed_data = PackedData::get_singleton();
 	packed_data = PackedData::get_singleton();
 	if (!packed_data) {
 	if (!packed_data) {
@@ -825,12 +821,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		} else if (I->get() == "--no-window") { // disable window creation (Windows only)
 		} else if (I->get() == "--no-window") { // disable window creation (Windows only)
 
 
 			OS::get_singleton()->set_no_window_mode(true);
 			OS::get_singleton()->set_no_window_mode(true);
-		} else if (I->get() == "--enable-vsync-via-compositor") {
-			window_vsync_via_compositor = true;
-			saw_vsync_via_compositor_override = true;
-		} else if (I->get() == "--disable-vsync-via-compositor") {
-			window_vsync_via_compositor = false;
-			saw_vsync_via_compositor_override = true;
 #endif
 #endif
 		} else if (I->get() == "--profiling") { // enable profiling
 		} else if (I->get() == "--profiling") { // enable profiling
 
 
@@ -1287,19 +1277,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
 		OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
 	}
 	}
 
 
-	use_vsync = GLOBAL_DEF_RST("display/window/vsync/use_vsync", true);
-	OS::get_singleton()->_use_vsync = use_vsync;
-
-	if (!saw_vsync_via_compositor_override) {
-		// If one of the command line options to enable/disable vsync via the
-		// window compositor ("--enable-vsync-via-compositor" or
-		// "--disable-vsync-via-compositor") was present then it overrides the
-		// project setting.
-		window_vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", false);
-	}
-
-	OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor;
-
 	/* todo restore
 	/* todo restore
     OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
     OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
     video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
     video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
@@ -1357,7 +1334,22 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	{
 	{
 		window_orientation = DisplayServer::ScreenOrientation(int(GLOBAL_DEF_BASIC("display/window/handheld/orientation", DisplayServer::ScreenOrientation::SCREEN_LANDSCAPE)));
 		window_orientation = DisplayServer::ScreenOrientation(int(GLOBAL_DEF_BASIC("display/window/handheld/orientation", DisplayServer::ScreenOrientation::SCREEN_LANDSCAPE)));
 	}
 	}
-
+	{
+		String vsync_mode = GLOBAL_DEF("display/window/vsync/vsync_mode", "Enabled");
+
+		if (vsync_mode == "Disabled") {
+			window_vsync_mode = DisplayServer::VSYNC_DISABLED;
+		} else if (vsync_mode == "Enabled") {
+			window_vsync_mode = DisplayServer::VSYNC_ENABLED;
+		} else if (vsync_mode == "Adaptive") {
+			window_vsync_mode = DisplayServer::VSYNC_ADAPTIVE;
+		} else if (vsync_mode == "Mailbox") {
+			window_vsync_mode = DisplayServer::VSYNC_MAILBOX;
+		} else {
+			WARN_PRINT("VSync mode unknown.");
+			window_vsync_mode = DisplayServer::VSYNC_ENABLED;
+		}
+	}
 	Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60));
 	Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60));
 	ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
 	ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
 			PropertyInfo(Variant::INT, "physics/common/physics_fps",
 			PropertyInfo(Variant::INT, "physics/common/physics_fps",
@@ -1550,14 +1542,14 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 		String rendering_driver; // temp broken
 		String rendering_driver; // temp broken
 
 
 		Error err;
 		Error err;
-		display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err);
+		display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
 		if (err != OK || display_server == nullptr) {
 		if (err != OK || display_server == nullptr) {
 			//ok i guess we can't use this display server, try other ones
 			//ok i guess we can't use this display server, try other ones
 			for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
 			for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
 				if (i == display_driver_idx) {
 				if (i == display_driver_idx) {
 					continue; //don't try the same twice
 					continue; //don't try the same twice
 				}
 				}
-				display_server = DisplayServer::create(i, rendering_driver, window_mode, window_flags, window_size, err);
+				display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
 				if (err == OK && display_server != nullptr) {
 				if (err == OK && display_server != nullptr) {
 					break;
 					break;
 				}
 				}

+ 0 - 6
misc/dist/linux/godot.6

@@ -85,12 +85,6 @@ Force low\-DPI mode (macOS and Windows only).
 .TP
 .TP
 \fB\-\-no\-window\fR
 \fB\-\-no\-window\fR
 Disable window creation (Windows only). Useful together with \fB\-\-script\fR.
 Disable window creation (Windows only). Useful together with \fB\-\-script\fR.
-.TP
-\fB\-\-enable\-vsync\-via\-compositor\fR
-When vsync is enabled, vsync via the OS' window compositor (Windows only).
-.TP
-\fB\-\-disable\-vsync\-via\-compositor\fR
-Disable vsync via the OS' window compositor (Windows only).
 .SS "Debug options:"
 .SS "Debug options:"
 .TP
 .TP
 \fB\-d\fR, \fB\-\-debug\fR
 \fB\-d\fR, \fB\-\-debug\fR

+ 0 - 2
misc/dist/shell/_godot.zsh-completion

@@ -51,8 +51,6 @@ _arguments \
   '--position[request window position]:position in X,Y format' \
   '--position[request window position]:position in X,Y format' \
   '--low-dpi[force low-DPI mode (macOS and Windows only)]' \
   '--low-dpi[force low-DPI mode (macOS and Windows only)]' \
   '--no-window[disable window creation (Windows only), useful together with --script]' \
   '--no-window[disable window creation (Windows only), useful together with --script]' \
-  "--enable-vsync-via-compositor[when Vsync is enabled, Vsync via the OS' window compositor (Windows only)]" \
-  "--disable-vsync-via-compositor[disable Vsync via the OS' window compositor (Windows only)]" \
   '(-d --debug)'{-d,--debug}'[debug (local stdout debugger)]' \
   '(-d --debug)'{-d,--debug}'[debug (local stdout debugger)]' \
   '(-b --breakpoints)'{-b,--breakpoints}'[specify the breakpoint list as source::line comma-separated pairs, no spaces (use %20 instead)]:breakpoint list' \
   '(-b --breakpoints)'{-b,--breakpoints}'[specify the breakpoint list as source::line comma-separated pairs, no spaces (use %20 instead)]:breakpoint list' \
   '--profiling[enable profiling in the script debugger]' \
   '--profiling[enable profiling in the script debugger]' \

+ 0 - 2
misc/dist/shell/godot.bash-completion

@@ -54,8 +54,6 @@ _complete_godot_options() {
 --position
 --position
 --low-dpi
 --low-dpi
 --no-window
 --no-window
---enable-vsync-via-compositor
---disable-vsync-via-compositor
 --debug
 --debug
 --breakpoints
 --breakpoints
 --profiling
 --profiling

+ 0 - 2
misc/dist/shell/godot.fish

@@ -61,8 +61,6 @@ complete -c godot -l resolution -d "Request window resolution" -x
 complete -c godot -l position -d "Request window position" -x
 complete -c godot -l position -d "Request window position" -x
 complete -c godot -l low-dpi -d "Force low-DPI mode (macOS and Windows only)"
 complete -c godot -l low-dpi -d "Force low-DPI mode (macOS and Windows only)"
 complete -c godot -l no-window -d "Disable window creation (Windows only), useful together with --script"
 complete -c godot -l no-window -d "Disable window creation (Windows only), useful together with --script"
-complete -c godot -l enable-vsync-via-compositor -d "When Vsync is enabled, Vsync via the OS' window compositor (Windows only)"
-complete -c godot -l disable-vsync-via-compositor -d "Disable Vsync via the OS' window compositor (Windows only)"
 
 
 # Debug options:
 # Debug options:
 complete -c godot -s d -l debug -d "Debug (local stdout debugger)"
 complete -c godot -s d -l debug -d "Debug (local stdout debugger)"

+ 20 - 5
platform/android/display_server_android.cpp

@@ -358,8 +358,8 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
 	return drivers;
 	return drivers;
 }
 }
 
 
-DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
-	DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
 	if (r_error != OK) {
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
 	}
 	}
@@ -377,10 +377,11 @@ void DisplayServerAndroid::reset_window() {
 		ERR_FAIL_COND(!native_window);
 		ERR_FAIL_COND(!native_window);
 
 
 		ERR_FAIL_COND(!context_vulkan);
 		ERR_FAIL_COND(!context_vulkan);
+		VSyncMode last_vsync_mode = context_vulkan->get_vsync_mode(MAIN_WINDOW_ID);
 		context_vulkan->window_destroy(MAIN_WINDOW_ID);
 		context_vulkan->window_destroy(MAIN_WINDOW_ID);
 
 
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
-		if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) {
+		if (context_vulkan->window_create(native_window, last_vsync_mode, display_size.width, display_size.height) == -1) {
 			memdelete(context_vulkan);
 			memdelete(context_vulkan);
 			context_vulkan = nullptr;
 			context_vulkan = nullptr;
 			ERR_FAIL_MSG("Failed to reset Vulkan window.");
 			ERR_FAIL_MSG("Failed to reset Vulkan window.");
@@ -402,7 +403,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
 	rect_changed_callback.call(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
 	rect_changed_callback.call(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
 }
 }
 
 
-DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	rendering_driver = p_rendering_driver;
 	rendering_driver = p_rendering_driver;
 
 
 	// TODO: rendering_driver is broken, change when different drivers are supported again
 	// TODO: rendering_driver is broken, change when different drivers are supported again
@@ -446,7 +447,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 		}
 		}
 
 
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
 		Size2i display_size = OS_Android::get_singleton()->get_display_size();
-		if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) {
+		if (context_vulkan->window_create(native_window, p_vsync_mode, display_size.width, display_size.height) == -1) {
 			memdelete(context_vulkan);
 			memdelete(context_vulkan);
 			context_vulkan = nullptr;
 			context_vulkan = nullptr;
 			ERR_FAIL_MSG("Failed to create Vulkan window.");
 			ERR_FAIL_MSG("Failed to create Vulkan window.");
@@ -901,3 +902,17 @@ void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape)
 DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
 DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
 	return cursor_shape;
 	return cursor_shape;
 }
 }
+
+void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+#if defined(VULKAN_ENABLED)
+	context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#endif
+}
+
+DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_window) const {
+#if defined(VULKAN_ENABLED)
+	return context_vulkan->get_vsync_mode(p_window);
+#else
+	return DisplayServer::VSYNC_ENABLED;
+#endif
+}

+ 4 - 2
platform/android/display_server_android.h

@@ -188,6 +188,8 @@ public:
 	virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
 	virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
 	virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
 	virtual bool can_any_window_draw() const;
 	virtual bool can_any_window_draw() const;
+	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID);
+	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const;
 
 
 	virtual void alert(const String &p_alert, const String &p_title);
 	virtual void alert(const String &p_alert, const String &p_title);
 
 
@@ -211,7 +213,7 @@ public:
 	void mouse_set_mode(MouseMode p_mode);
 	void mouse_set_mode(MouseMode p_mode);
 	MouseMode mouse_get_mode() const;
 	MouseMode mouse_get_mode() const;
 
 
-	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	static Vector<String> get_rendering_drivers_func();
 	static Vector<String> get_rendering_drivers_func();
 	static void register_android_driver();
 	static void register_android_driver();
 
 
@@ -221,7 +223,7 @@ public:
 	virtual Point2i mouse_get_position() const;
 	virtual Point2i mouse_get_position() const;
 	virtual MouseButton mouse_get_button_state() const;
 	virtual MouseButton mouse_get_button_state() const;
 
 
-	DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerAndroid();
 	~DisplayServerAndroid();
 };
 };
 
 

+ 2 - 2
platform/android/vulkan/vulkan_context_android.cpp

@@ -36,7 +36,7 @@ const char *VulkanContextAndroid::_get_platform_surface_extension() const {
 	return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
 	return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
 }
 }
 
 
-int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, int p_height) {
+int VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height) {
 	VkAndroidSurfaceCreateInfoKHR createInfo;
 	VkAndroidSurfaceCreateInfoKHR createInfo;
 	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
 	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
 	createInfo.pNext = nullptr;
 	createInfo.pNext = nullptr;
@@ -49,7 +49,7 @@ int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, in
 		ERR_FAIL_V_MSG(-1, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
 		ERR_FAIL_V_MSG(-1, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
 	}
 	}
 
 
-	return _window_create(DisplayServer::MAIN_WINDOW_ID, surface, p_width, p_height);
+	return _window_create(DisplayServer::MAIN_WINDOW_ID, p_vsync_mode, surface, p_width, p_height);
 }
 }
 
 
 bool VulkanContextAndroid::_use_validation_layers() {
 bool VulkanContextAndroid::_use_validation_layers() {

+ 1 - 1
platform/android/vulkan/vulkan_context_android.h

@@ -39,7 +39,7 @@ class VulkanContextAndroid : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const override;
 	virtual const char *_get_platform_surface_extension() const override;
 
 
 public:
 public:
-	int window_create(ANativeWindow *p_window, int p_width, int p_height);
+	int window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height);
 
 
 	VulkanContextAndroid() = default;
 	VulkanContextAndroid() = default;
 	~VulkanContextAndroid() override = default;
 	~VulkanContextAndroid() override = default;

+ 5 - 2
platform/iphone/display_server_iphone.h

@@ -67,7 +67,7 @@ class DisplayServerIPhone : public DisplayServer {
 
 
 	void perform_event(const Ref<InputEvent> &p_event);
 	void perform_event(const Ref<InputEvent> &p_event);
 
 
-	DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerIPhone();
 	~DisplayServerIPhone();
 
 
 public:
 public:
@@ -76,7 +76,7 @@ public:
 	static DisplayServerIPhone *get_singleton();
 	static DisplayServerIPhone *get_singleton();
 
 
 	static void register_iphone_driver();
 	static void register_iphone_driver();
-	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	static Vector<String> get_rendering_drivers_func();
 	static Vector<String> get_rendering_drivers_func();
 
 
 	// MARK: - Events
 	// MARK: - Events
@@ -176,6 +176,9 @@ public:
 
 
 	virtual bool can_any_window_draw() const override;
 	virtual bool can_any_window_draw() const override;
 
 
+	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
+	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
+
 	virtual bool screen_is_touchscreen(int p_screen) const override;
 	virtual bool screen_is_touchscreen(int p_screen) const override;
 
 
 	virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override;
 	virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override;

+ 20 - 4
platform/iphone/display_server_iphone.mm

@@ -48,7 +48,7 @@ DisplayServerIPhone *DisplayServerIPhone::get_singleton() {
 	return (DisplayServerIPhone *)DisplayServer::get_singleton();
 	return (DisplayServerIPhone *)DisplayServer::get_singleton();
 }
 }
 
 
-DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	rendering_driver = p_rendering_driver;
 	rendering_driver = p_rendering_driver;
 
 
 #if defined(OPENGL_ENABLED)
 #if defined(OPENGL_ENABLED)
@@ -108,7 +108,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Displ
 		}
 		}
 
 
 		Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
 		Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
-		if (context_vulkan->window_create(MAIN_WINDOW_ID, layer, size.width, size.height) != OK) {
+		if (context_vulkan->window_create(MAIN_WINDOW_ID, p_vsync_mode, layer, size.width, size.height) != OK) {
 			memdelete(context_vulkan);
 			memdelete(context_vulkan);
 			context_vulkan = nullptr;
 			context_vulkan = nullptr;
 			ERR_FAIL_MSG("Failed to create Vulkan window.");
 			ERR_FAIL_MSG("Failed to create Vulkan window.");
@@ -147,8 +147,8 @@ DisplayServerIPhone::~DisplayServerIPhone() {
 #endif
 #endif
 }
 }
 
 
-DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
-	return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 }
 }
 
 
 Vector<String> DisplayServerIPhone::get_rendering_drivers_func() {
 Vector<String> DisplayServerIPhone::get_rendering_drivers_func() {
@@ -581,3 +581,19 @@ void DisplayServerIPhone::resize_window(CGSize viewSize) {
 	Variant resize_rect = Rect2i(Point2i(), size);
 	Variant resize_rect = Rect2i(Point2i(), size);
 	_window_callback(window_resize_callback, resize_rect);
 	_window_callback(window_resize_callback, resize_rect);
 }
 }
+
+void DisplayServerIPhone::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#endif
+}
+
+DisplayServer::VSyncMode DisplayServerIPhone::window_get_vsync_mode(WindowID p_window) const {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	return context_vulkan->get_vsync_mode(p_window);
+#else
+	return DisplayServer::VSYNC_ENABLED;
+#endif
+}

+ 1 - 1
platform/iphone/vulkan_context_iphone.h

@@ -39,7 +39,7 @@ class VulkanContextIPhone : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 	virtual const char *_get_platform_surface_extension() const;
 
 
 public:
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height);
+	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height);
 
 
 	VulkanContextIPhone();
 	VulkanContextIPhone();
 	~VulkanContextIPhone();
 	~VulkanContextIPhone();

+ 2 - 2
platform/iphone/vulkan_context_iphone.mm

@@ -35,7 +35,7 @@ const char *VulkanContextIPhone::_get_platform_surface_extension() const {
 	return VK_MVK_IOS_SURFACE_EXTENSION_NAME;
 	return VK_MVK_IOS_SURFACE_EXTENSION_NAME;
 }
 }
 
 
-Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height) {
+Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) {
 	VkIOSSurfaceCreateInfoMVK createInfo;
 	VkIOSSurfaceCreateInfoMVK createInfo;
 	createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.pNext = nullptr;
 	createInfo.pNext = nullptr;
@@ -47,7 +47,7 @@ Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CA
 			vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 			vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 
 
-	return _window_create(p_window_id, surface, p_width, p_height);
+	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
 }
 }
 
 
 VulkanContextIPhone::VulkanContextIPhone() {}
 VulkanContextIPhone::VulkanContextIPhone() {}

+ 24 - 8
platform/linuxbsd/display_server_x11.cpp

@@ -855,10 +855,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
 	return ret;
 	return ret;
 }
 }
 
 
-DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
-	WindowID id = _create_window(p_mode, p_flags, p_rect);
+	WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 		if (p_flags & (1 << i)) {
 		if (p_flags & (1 << i)) {
 			window_set_flag(WindowFlags(i), true, id);
 			window_set_flag(WindowFlags(i), true, id);
@@ -3641,6 +3641,22 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
 	XSetErrorHandler(oldHandler);
 	XSetErrorHandler(oldHandler);
 }
 }
 
 
+void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#endif
+}
+
+DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	return context_vulkan->get_vsync_mode(p_window);
+#else
+	return DisplayServer::VSYNC_ENABLED;
+#endif
+}
+
 Vector<String> DisplayServerX11::get_rendering_drivers_func() {
 Vector<String> DisplayServerX11::get_rendering_drivers_func() {
 	Vector<String> drivers;
 	Vector<String> drivers;
 
 
@@ -3654,8 +3670,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
 	return drivers;
 	return drivers;
 }
 }
 
 
-DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
-	DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
 	if (r_error != OK) {
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
 				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
 				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
@@ -3664,7 +3680,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
 	return ds;
 	return ds;
 }
 }
 
 
-DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	//Create window
 	//Create window
 
 
 	long visualMask = VisualScreenMask;
 	long visualMask = VisualScreenMask;
@@ -3828,7 +3844,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 
 
 #if defined(VULKAN_ENABLED)
 #if defined(VULKAN_ENABLED)
 		if (context_vulkan) {
 		if (context_vulkan) {
-			Error err = context_vulkan->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+			Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
 			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
 			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
 		}
 		}
 #endif
 #endif
@@ -3865,7 +3881,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 	return id;
 	return id;
 }
 }
 
 
-DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
 	Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
 
 
 	r_error = OK;
 	r_error = OK;
@@ -4101,7 +4117,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	Point2i window_position(
 	Point2i window_position(
 			(screen_get_size(0).width - p_resolution.width) / 2,
 			(screen_get_size(0).width - p_resolution.width) / 2,
 			(screen_get_size(0).height - p_resolution.height) / 2);
 			(screen_get_size(0).height - p_resolution.height) / 2);
-	WindowID main_window = _create_window(p_mode, p_flags, Rect2i(window_position, p_resolution));
+	WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
 	if (main_window == INVALID_WINDOW_ID) {
 	if (main_window == INVALID_WINDOW_ID) {
 		r_error = ERR_CANT_CREATE;
 		r_error = ERR_CANT_CREATE;
 		return;
 		return;

+ 7 - 4
platform/linuxbsd/display_server_x11.h

@@ -152,7 +152,7 @@ class DisplayServerX11 : public DisplayServer {
 	Map<WindowID, WindowData> windows;
 	Map<WindowID, WindowData> windows;
 
 
 	WindowID window_id_counter = MAIN_WINDOW_ID;
 	WindowID window_id_counter = MAIN_WINDOW_ID;
-	WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect);
+	WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
 
 
 	String internal_clipboard;
 	String internal_clipboard;
 	Window xdnd_source_window;
 	Window xdnd_source_window;
@@ -307,7 +307,7 @@ public:
 
 
 	virtual Vector<DisplayServer::WindowID> get_window_list() const;
 	virtual Vector<DisplayServer::WindowID> get_window_list() const;
 
 
-	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
 	virtual void show_window(WindowID p_id);
 	virtual void show_window(WindowID p_id);
 	virtual void delete_sub_window(WindowID p_id);
 	virtual void delete_sub_window(WindowID p_id);
 
 
@@ -362,6 +362,9 @@ public:
 	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
 
 
+	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
+	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
+
 	virtual void cursor_set_shape(CursorShape p_shape);
 	virtual void cursor_set_shape(CursorShape p_shape);
 	virtual CursorShape cursor_get_shape() const;
 	virtual CursorShape cursor_get_shape() const;
 	virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
 	virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
@@ -383,12 +386,12 @@ public:
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_icon(const Ref<Image> &p_icon);
 	virtual void set_icon(const Ref<Image> &p_icon);
 
 
-	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	static Vector<String> get_rendering_drivers_func();
 	static Vector<String> get_rendering_drivers_func();
 
 
 	static void register_x11_driver();
 	static void register_x11_driver();
 
 
-	DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerX11();
 	~DisplayServerX11();
 };
 };
 
 

+ 2 - 2
platform/linuxbsd/vulkan_context_x11.cpp

@@ -35,7 +35,7 @@ const char *VulkanContextX11::_get_platform_surface_extension() const {
 	return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
 	return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
 }
 }
 
 
-Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
+Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height) {
 	VkXlibSurfaceCreateInfoKHR createInfo;
 	VkXlibSurfaceCreateInfoKHR createInfo;
 	createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
 	createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
 	createInfo.pNext = nullptr;
 	createInfo.pNext = nullptr;
@@ -46,7 +46,7 @@ Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Win
 	VkSurfaceKHR surface;
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, surface, p_width, p_height);
+	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
 }
 }
 
 
 VulkanContextX11::VulkanContextX11() {
 VulkanContextX11::VulkanContextX11() {

+ 1 - 1
platform/linuxbsd/vulkan_context_x11.h

@@ -38,7 +38,7 @@ class VulkanContextX11 : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 	virtual const char *_get_platform_surface_extension() const;
 
 
 public:
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
+	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height);
 
 
 	VulkanContextX11();
 	VulkanContextX11();
 	~VulkanContextX11();
 	~VulkanContextX11();

+ 7 - 4
platform/osx/display_server_osx.h

@@ -145,7 +145,7 @@ public:
 
 
 	WindowID window_id_counter = MAIN_WINDOW_ID;
 	WindowID window_id_counter = MAIN_WINDOW_ID;
 
 
-	WindowID _create_window(WindowMode p_mode, const Rect2i &p_rect);
+	WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect);
 	void _update_window(WindowData p_wd);
 	void _update_window(WindowData p_wd);
 	void _send_window_event(const WindowData &wd, WindowEvent p_event);
 	void _send_window_event(const WindowData &wd, WindowEvent p_event);
 	static void _dispatch_input_events(const Ref<InputEvent> &p_event);
 	static void _dispatch_input_events(const Ref<InputEvent> &p_event);
@@ -232,7 +232,7 @@ public:
 
 
 	virtual Vector<int> get_window_list() const override;
 	virtual Vector<int> get_window_list() const override;
 
 
-	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
+	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
 	virtual void show_window(WindowID p_id) override;
 	virtual void show_window(WindowID p_id) override;
 	virtual void delete_sub_window(WindowID p_id) override;
 	virtual void delete_sub_window(WindowID p_id) override;
 
 
@@ -286,6 +286,9 @@ public:
 	virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
 	virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
 	virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
 	virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
 
 
+	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
+	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
+
 	virtual Point2i ime_get_selection() const override;
 	virtual Point2i ime_get_selection() const override;
 	virtual String ime_get_text() const override;
 	virtual String ime_get_text() const override;
 
 
@@ -314,12 +317,12 @@ public:
 	virtual void console_set_visible(bool p_enabled) override;
 	virtual void console_set_visible(bool p_enabled) override;
 	virtual bool is_console_visible() const override;
 	virtual bool is_console_visible() const override;
 
 
-	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	static Vector<String> get_rendering_drivers_func();
 	static Vector<String> get_rendering_drivers_func();
 
 
 	static void register_osx_driver();
 	static void register_osx_driver();
 
 
-	DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerOSX();
 	~DisplayServerOSX();
 };
 };
 
 

+ 24 - 8
platform/osx/display_server_osx.mm

@@ -2388,10 +2388,10 @@ Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
 	return ret;
 	return ret;
 }
 }
 
 
-DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
-	WindowID id = _create_window(p_mode, p_rect);
+	WindowID id = _create_window(p_mode, p_vsync_mode, p_rect);
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 		if (p_flags & (1 << i)) {
 		if (p_flags & (1 << i)) {
 			window_set_flag(WindowFlags(i), true, id);
 			window_set_flag(WindowFlags(i), true, id);
@@ -3546,6 +3546,22 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
 	[nsimg release];
 	[nsimg release];
 }
 }
 
 
+void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#endif
+}
+
+DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	return context_vulkan->get_vsync_mode(p_window);
+#else
+	return DisplayServer::VSYNC_ENABLED;
+#endif
+}
+
 Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
 Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
 	Vector<String> drivers;
 	Vector<String> drivers;
 
 
@@ -3596,15 +3612,15 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co
 	return windows[p_window].instance_id;
 	return windows[p_window].instance_id;
 }
 }
 
 
-DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
-	DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
 	if (r_error != OK) {
 		ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
 		ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
 	}
 	}
 	return ds;
 	return ds;
 }
 }
 
 
-DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, const Rect2i &p_rect) {
+DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) {
 	WindowID id;
 	WindowID id;
 	const float scale = screen_get_max_scale();
 	const float scale = screen_get_max_scale();
 	{
 	{
@@ -3651,7 +3667,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c
 #if defined(VULKAN_ENABLED)
 #if defined(VULKAN_ENABLED)
 		if (rendering_driver == "vulkan") {
 		if (rendering_driver == "vulkan") {
 			if (context_vulkan) {
 			if (context_vulkan) {
-				Error err = context_vulkan->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
+				Error err = context_vulkan->window_create(window_id_counter, p_vsync_mode, wd.window_view, p_rect.size.width, p_rect.size.height);
 				ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context");
 				ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context");
 			}
 			}
 		}
 		}
@@ -3750,7 +3766,7 @@ bool DisplayServerOSX::is_console_visible() const {
 	return isatty(STDIN_FILENO);
 	return isatty(STDIN_FILENO);
 }
 }
 
 
-DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
 	Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
 
 
 	r_error = OK;
 	r_error = OK;
@@ -3886,7 +3902,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 	Point2i window_position(
 	Point2i window_position(
 			screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
 			screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
 			screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
 			screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
-	WindowID main_window = _create_window(p_mode, Rect2i(window_position, p_resolution));
+	WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution));
 	ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
 	ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 		if (p_flags & (1 << i)) {
 		if (p_flags & (1 << i)) {

+ 1 - 1
platform/osx/vulkan_context_osx.h

@@ -38,7 +38,7 @@ class VulkanContextOSX : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 	virtual const char *_get_platform_surface_extension() const;
 
 
 public:
 public:
-	Error window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height);
+	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height);
 
 
 	VulkanContextOSX();
 	VulkanContextOSX();
 	~VulkanContextOSX();
 	~VulkanContextOSX();

+ 2 - 2
platform/osx/vulkan_context_osx.mm

@@ -35,7 +35,7 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const {
 	return VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
 	return VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
 }
 }
 
 
-Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height) {
+Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) {
 	VkMacOSSurfaceCreateInfoMVK createInfo;
 	VkMacOSSurfaceCreateInfoMVK createInfo;
 	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.pNext = nullptr;
 	createInfo.pNext = nullptr;
@@ -45,7 +45,7 @@ Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_
 	VkSurfaceKHR surface;
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 	VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
 	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, surface, p_width, p_height);
+	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
 }
 }
 
 
 VulkanContextOSX::VulkanContextOSX() {
 VulkanContextOSX::VulkanContextOSX() {

+ 1 - 35
platform/windows/context_gl_windows.cpp

@@ -66,46 +66,13 @@ int ContextGL_Windows::get_window_height() {
 	return OS::get_singleton()->get_video_mode().height;
 	return OS::get_singleton()->get_video_mode().height;
 }
 }
 
 
-bool ContextGL_Windows::should_vsync_via_compositor() {
-	if (OS::get_singleton()->is_window_fullscreen() || !OS::get_singleton()->is_vsync_via_compositor_enabled()) {
-		return false;
-	}
-
-	// Note: All Windows versions supported by Godot have a compositor.
-	// It can be disabled on earlier Windows versions.
-	BOOL dwm_enabled;
-
-	if (SUCCEEDED(DwmIsCompositionEnabled(&dwm_enabled))) {
-		return dwm_enabled;
-	}
-
-	return false;
-}
-
 void ContextGL_Windows::swap_buffers() {
 void ContextGL_Windows::swap_buffers() {
 	SwapBuffers(hDC);
 	SwapBuffers(hDC);
-
-	if (use_vsync) {
-		bool vsync_via_compositor_now = should_vsync_via_compositor();
-
-		if (vsync_via_compositor_now && wglGetSwapIntervalEXT() == 0) {
-			DwmFlush();
-		}
-
-		if (vsync_via_compositor_now != vsync_via_compositor) {
-			// The previous frame had a different operating mode than this
-			// frame. Set the 'vsync_via_compositor' member variable and the
-			// OpenGL swap interval to their proper values.
-			set_use_vsync(true);
-		}
-	}
 }
 }
 
 
 void ContextGL_Windows::set_use_vsync(bool p_use) {
 void ContextGL_Windows::set_use_vsync(bool p_use) {
-	vsync_via_compositor = p_use && should_vsync_via_compositor();
-
 	if (wglSwapIntervalEXT) {
 	if (wglSwapIntervalEXT) {
-		int swap_interval = (p_use && !vsync_via_compositor) ? 1 : 0;
+		int swap_interval = p_use ? 1 : 0;
 		wglSwapIntervalEXT(swap_interval);
 		wglSwapIntervalEXT(swap_interval);
 	}
 	}
 
 
@@ -210,7 +177,6 @@ ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) {
 	opengl_3_context = p_opengl_3_context;
 	opengl_3_context = p_opengl_3_context;
 	hWnd = hwnd;
 	hWnd = hwnd;
 	use_vsync = false;
 	use_vsync = false;
-	vsync_via_compositor = false;
 	pixel_format = 0;
 	pixel_format = 0;
 }
 }
 
 

+ 0 - 3
platform/windows/context_gl_windows.h

@@ -50,13 +50,10 @@ class ContextGL_Windows {
 	HWND hWnd;
 	HWND hWnd;
 	bool opengl_3_context;
 	bool opengl_3_context;
 	bool use_vsync;
 	bool use_vsync;
-	bool vsync_via_compositor;
 
 
 	PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
 	PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
 	PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
 	PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
 
 
-	static bool should_vsync_via_compositor();
-
 public:
 public:
 	void release_current();
 	void release_current();
 
 

+ 20 - 12
platform/windows/display_server_windows.cpp

@@ -477,10 +477,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons
 	return INVALID_WINDOW_ID;
 	return INVALID_WINDOW_ID;
 }
 }
 
 
-DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
-	WindowID window_id = _create_window(p_mode, p_flags, p_rect);
+	WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
 	ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window.");
 	ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window.");
 
 
 	WindowData &wd = windows[window_id];
 	WindowData &wd = windows[window_id];
@@ -1697,11 +1697,20 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
 	SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
 	SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
 }
 }
 
 
-void DisplayServerWindows::vsync_set_use_via_compositor(bool p_enable) {
+void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#endif
 }
 }
 
 
-bool DisplayServerWindows::vsync_is_using_via_compositor() const {
-	return false;
+DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
+	_THREAD_SAFE_METHOD_
+#if defined(VULKAN_ENABLED)
+	return context_vulkan->get_vsync_mode(p_window);
+#else
+	return DisplayServer::VSYNC_ENABLED;
+#endif
 }
 }
 
 
 void DisplayServerWindows::set_context(Context p_context) {
 void DisplayServerWindows::set_context(Context p_context) {
@@ -2968,7 +2977,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
 	}
 	}
 }
 }
 
 
-DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	DWORD dwExStyle;
 	DWORD dwExStyle;
 	DWORD dwStyle;
 	DWORD dwStyle;
 
 
@@ -3030,7 +3039,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 #ifdef VULKAN_ENABLED
 #ifdef VULKAN_ENABLED
 
 
 		if (rendering_driver == "vulkan") {
 		if (rendering_driver == "vulkan") {
-			if (context_vulkan->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
+			if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
 				memdelete(context_vulkan);
 				memdelete(context_vulkan);
 				context_vulkan = nullptr;
 				context_vulkan = nullptr;
 				windows.erase(id);
 				windows.erase(id);
@@ -3151,7 +3160,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
 	}
 	}
 }
 }
 
 
-DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	drop_events = false;
 	drop_events = false;
 	key_event_pos = 0;
 	key_event_pos = 0;
 
 
@@ -3270,7 +3279,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 		}
 		}
 
 
 		context_gles2->set_use_vsync(video_mode.use_vsync);
 		context_gles2->set_use_vsync(video_mode.use_vsync);
-		set_vsync_via_compositor(video_mode.vsync_via_compositor);
 
 
 		if (RasterizerGLES2::is_viable() == OK) {
 		if (RasterizerGLES2::is_viable() == OK) {
 			RasterizerGLES2::register_config();
 			RasterizerGLES2::register_config();
@@ -3286,7 +3294,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 			(screen_get_size(0).width - p_resolution.width) / 2,
 			(screen_get_size(0).width - p_resolution.width) / 2,
 			(screen_get_size(0).height - p_resolution.height) / 2);
 			(screen_get_size(0).height - p_resolution.height) / 2);
 
 
-	WindowID main_window = _create_window(p_mode, 0, Rect2i(window_position, p_resolution));
+	WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
 	ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
 	ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
 
 
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
@@ -3347,8 +3355,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
 	return drivers;
 	return drivers;
 }
 }
 
 
-DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
-	DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
 	if (r_error != OK) {
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
 		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
 				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
 				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",

+ 7 - 7
platform/windows/display_server_windows.h

@@ -389,7 +389,7 @@ class DisplayServerWindows : public DisplayServer {
 
 
 	JoypadWindows *joypad;
 	JoypadWindows *joypad;
 
 
-	WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect);
+	WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
 	WindowID window_id_counter = MAIN_WINDOW_ID;
 	WindowID window_id_counter = MAIN_WINDOW_ID;
 	Map<WindowID, WindowData> windows;
 	Map<WindowID, WindowData> windows;
 
 
@@ -469,7 +469,7 @@ public:
 
 
 	virtual Vector<DisplayServer::WindowID> get_window_list() const;
 	virtual Vector<DisplayServer::WindowID> get_window_list() const;
 
 
-	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
 	virtual void show_window(WindowID p_window);
 	virtual void show_window(WindowID p_window);
 	virtual void delete_sub_window(WindowID p_window);
 	virtual void delete_sub_window(WindowID p_window);
 
 
@@ -525,6 +525,9 @@ public:
 	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
 
 
+	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
+	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
+
 	virtual void console_set_visible(bool p_enabled);
 	virtual void console_set_visible(bool p_enabled);
 	virtual bool is_console_visible() const;
 	virtual bool is_console_visible() const;
 
 
@@ -558,16 +561,13 @@ public:
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_icon(const Ref<Image> &p_icon);
 	virtual void set_icon(const Ref<Image> &p_icon);
 
 
-	virtual void vsync_set_use_via_compositor(bool p_enable);
-	virtual bool vsync_is_using_via_compositor() const;
-
 	virtual void set_context(Context p_context);
 	virtual void set_context(Context p_context);
 
 
-	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	static Vector<String> get_rendering_drivers_func();
 	static Vector<String> get_rendering_drivers_func();
 	static void register_windows_driver();
 	static void register_windows_driver();
 
 
-	DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerWindows();
 	~DisplayServerWindows();
 };
 };
 
 

+ 2 - 3
platform/windows/vulkan_context_win.cpp

@@ -35,18 +35,17 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const {
 	return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
 	return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
 }
 }
 
 
-int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
+int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
 	VkWin32SurfaceCreateInfoKHR createInfo;
 	VkWin32SurfaceCreateInfoKHR createInfo;
 	createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
 	createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
 	createInfo.pNext = nullptr;
 	createInfo.pNext = nullptr;
 	createInfo.flags = 0;
 	createInfo.flags = 0;
 	createInfo.hinstance = p_instance;
 	createInfo.hinstance = p_instance;
 	createInfo.hwnd = p_window;
 	createInfo.hwnd = p_window;
-
 	VkSurfaceKHR surface;
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	ERR_FAIL_COND_V(err, -1);
 	ERR_FAIL_COND_V(err, -1);
-	return _window_create(p_window_id, surface, p_width, p_height);
+	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
 }
 }
 
 
 VulkanContextWindows::VulkanContextWindows() {
 VulkanContextWindows::VulkanContextWindows() {

+ 1 - 1
platform/windows/vulkan_context_win.h

@@ -38,7 +38,7 @@ class VulkanContextWindows : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 	virtual const char *_get_platform_surface_extension() const;
 
 
 public:
 public:
-	int window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
+	int window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
 
 
 	VulkanContextWindows();
 	VulkanContextWindows();
 	~VulkanContextWindows();
 	~VulkanContextWindows();

+ 2 - 1
scene/main/window.cpp

@@ -227,7 +227,8 @@ void Window::_make_window() {
 		}
 		}
 	}
 	}
 
 
-	window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
+	DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID);
+	window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size));
 	ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
 	ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
 	DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
 	DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
 	DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
 	DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);

+ 17 - 32
servers/display_server.cpp

@@ -35,7 +35,6 @@
 #include "servers/display_server_headless.h"
 #include "servers/display_server_headless.h"
 
 
 DisplayServer *DisplayServer::singleton = nullptr;
 DisplayServer *DisplayServer::singleton = nullptr;
-DisplayServer::SwitchVSyncCallbackInThread DisplayServer::switch_vsync_function = nullptr;
 
 
 bool DisplayServer::hidpi_allowed = false;
 bool DisplayServer::hidpi_allowed = false;
 
 
@@ -185,7 +184,7 @@ bool DisplayServer::screen_is_kept_on() const {
 	return false;
 	return false;
 }
 }
 
 
-DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
 	ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
 	ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
 }
 }
 
 
@@ -309,29 +308,13 @@ void DisplayServer::set_icon(const Ref<Image> &p_icon) {
 	WARN_PRINT("Icon not supported by this display server.");
 	WARN_PRINT("Icon not supported by this display server.");
 }
 }
 
 
-void DisplayServer::_set_use_vsync(bool p_enable) {
-	WARN_PRINT("VSync not supported by this display server.");
+void DisplayServer::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
+	WARN_PRINT("Changing the VSync mode is not supported by this display server.");
 }
 }
 
 
-void DisplayServer::vsync_set_enabled(bool p_enable) {
-	vsync_enabled = p_enable;
-	if (switch_vsync_function) { //if a function was set, use function
-		switch_vsync_function(p_enable);
-	} else { //otherwise just call here
-		_set_use_vsync(p_enable);
-	}
-}
-
-bool DisplayServer::vsync_is_enabled() const {
-	return vsync_enabled;
-}
-
-void DisplayServer::vsync_set_use_via_compositor(bool p_enable) {
-	WARN_PRINT("VSync via compositor not supported by this display server.");
-}
-
-bool DisplayServer::vsync_is_using_via_compositor() const {
-	return false;
+DisplayServer::VSyncMode DisplayServer::window_get_vsync_mode(WindowID p_window) const {
+	WARN_PRINT("Changing the VSync mode is not supported by this display server.");
+	return VSyncMode::VSYNC_ENABLED;
 }
 }
 
 
 void DisplayServer::set_context(Context p_context) {
 void DisplayServer::set_context(Context p_context) {
@@ -394,7 +377,7 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
 	ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
 	ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position);
 	ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position);
 
 
-	ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i()));
+	ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "vsync_mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i()));
 	ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
 	ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
 
 
 	ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
@@ -441,6 +424,9 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID));
 
 
+	ClassDB::bind_method(D_METHOD("window_set_vsync_mode", "vsync_mode", "window_id"), &DisplayServer::window_set_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_get_vsync_mode", "window_id"), &DisplayServer::window_get_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
+
 	ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection);
 	ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection);
 	ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text);
 	ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text);
 
 
@@ -472,12 +458,6 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events);
 	ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events);
 	ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);
 	ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);
 
 
-	ClassDB::bind_method(D_METHOD("vsync_set_enabled", "enabled"), &DisplayServer::vsync_set_enabled);
-	ClassDB::bind_method(D_METHOD("vsync_is_enabled"), &DisplayServer::vsync_is_enabled);
-
-	ClassDB::bind_method(D_METHOD("vsync_set_use_via_compositor", "enabled"), &DisplayServer::vsync_set_use_via_compositor);
-	ClassDB::bind_method(D_METHOD("vsync_is_using_via_compositor"), &DisplayServer::vsync_is_using_via_compositor);
-
 	ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon);
 	ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon);
 	ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon);
 	ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon);
 
 
@@ -561,6 +541,11 @@ void DisplayServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
+
+	BIND_ENUM_CONSTANT(VSYNC_DISABLED);
+	BIND_ENUM_CONSTANT(VSYNC_ENABLED);
+	BIND_ENUM_CONSTANT(VSYNC_ADAPTIVE);
+	BIND_ENUM_CONSTANT(VSYNC_MAILBOX);
 }
 }
 
 
 void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) {
 void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) {
@@ -587,9 +572,9 @@ Vector<String> DisplayServer::get_create_function_rendering_drivers(int p_index)
 	return server_create_functions[p_index].get_rendering_drivers_function();
 	return server_create_functions[p_index].get_rendering_drivers_function();
 }
 }
 
 
-DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
 	ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
-	return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_flags, p_resolution, r_error);
+	return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error);
 }
 }
 
 
 void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) {
 void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) {

+ 14 - 17
servers/display_server.h

@@ -42,7 +42,6 @@ class DisplayServer : public Object {
 	GDCLASS(DisplayServer, Object)
 	GDCLASS(DisplayServer, Object)
 
 
 	static DisplayServer *singleton;
 	static DisplayServer *singleton;
-	bool vsync_enabled = true;
 	static bool hidpi_allowed;
 	static bool hidpi_allowed;
 
 
 public:
 public:
@@ -57,7 +56,14 @@ public:
 		WINDOW_MODE_FULLSCREEN
 		WINDOW_MODE_FULLSCREEN
 	};
 	};
 
 
-	typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, uint32_t, const Size2i &, Error &r_error);
+	enum VSyncMode {
+		VSYNC_DISABLED,
+		VSYNC_ENABLED,
+		VSYNC_ADAPTIVE,
+		VSYNC_MAILBOX
+	};
+
+	typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Size2i &, Error &r_error);
 	typedef Vector<String> (*GetRenderingDriversFunction)();
 	typedef Vector<String> (*GetRenderingDriversFunction)();
 
 
 private:
 private:
@@ -84,7 +90,6 @@ protected:
 	static int server_create_count;
 	static int server_create_count;
 
 
 	friend class RendererViewport;
 	friend class RendererViewport;
-	virtual void _set_use_vsync(bool p_enable);
 
 
 public:
 public:
 	enum Feature {
 	enum Feature {
@@ -221,7 +226,7 @@ public:
 		WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS)
 		WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS)
 	};
 	};
 
 
-	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
 	virtual void show_window(WindowID p_id);
 	virtual void show_window(WindowID p_id);
 	virtual void delete_sub_window(WindowID p_id);
 	virtual void delete_sub_window(WindowID p_id);
 
 
@@ -272,6 +277,9 @@ public:
 	virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) = 0;
 	virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) = 0;
 	virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const = 0;
 	virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const = 0;
 
 
+	virtual void window_set_vsync_mode(VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID);
+	virtual VSyncMode window_get_vsync_mode(WindowID p_window) const;
+
 	virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const = 0;
 	virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const = 0;
 
 
 	virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) = 0;
 	virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) = 0;
@@ -352,18 +360,6 @@ public:
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_native_icon(const String &p_filename);
 	virtual void set_icon(const Ref<Image> &p_icon);
 	virtual void set_icon(const Ref<Image> &p_icon);
 
 
-	typedef void (*SwitchVSyncCallbackInThread)(bool);
-
-	static SwitchVSyncCallbackInThread switch_vsync_function;
-
-	void vsync_set_enabled(bool p_enable);
-	bool vsync_is_enabled() const;
-
-	virtual void vsync_set_use_via_compositor(bool p_enable);
-	virtual bool vsync_is_using_via_compositor() const;
-
-	//real, actual overridable function to switch vsync, which needs to be called from graphics thread if needed
-
 	enum Context {
 	enum Context {
 		CONTEXT_EDITOR,
 		CONTEXT_EDITOR,
 		CONTEXT_PROJECTMAN,
 		CONTEXT_PROJECTMAN,
@@ -376,7 +372,7 @@ public:
 	static int get_create_function_count();
 	static int get_create_function_count();
 	static const char *get_create_function_name(int p_index);
 	static const char *get_create_function_name(int p_index);
 	static Vector<String> get_create_function_rendering_drivers(int p_index);
 	static Vector<String> get_create_function_rendering_drivers(int p_index);
-	static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 
 
 	DisplayServer();
 	DisplayServer();
 	~DisplayServer();
 	~DisplayServer();
@@ -389,5 +385,6 @@ VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation)
 VARIANT_ENUM_CAST(DisplayServer::WindowMode)
 VARIANT_ENUM_CAST(DisplayServer::WindowMode)
 VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
 VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
 VARIANT_ENUM_CAST(DisplayServer::CursorShape)
 VARIANT_ENUM_CAST(DisplayServer::CursorShape)
+VARIANT_ENUM_CAST(DisplayServer::VSyncMode)
 
 
 #endif // DISPLAY_SERVER_H
 #endif // DISPLAY_SERVER_H

+ 1 - 1
servers/display_server_headless.h

@@ -45,7 +45,7 @@ private:
 		return drivers;
 		return drivers;
 	}
 	}
 
 
-	static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+	static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 		r_error = OK;
 		r_error = OK;
 		RasterizerDummy::make_current();
 		RasterizerDummy::make_current();
 		return memnew(DisplayServerHeadless());
 		return memnew(DisplayServerHeadless());

+ 3 - 3
servers/rendering/renderer_viewport.cpp

@@ -1116,9 +1116,9 @@ void RendererViewport::set_default_clear_color(const Color &p_color) {
 	RSG::storage->set_default_clear_color(p_color);
 	RSG::storage->set_default_clear_color(p_color);
 }
 }
 
 
-//workaround for setting this on thread
-void RendererViewport::call_set_use_vsync(bool p_enable) {
-	DisplayServer::get_singleton()->_set_use_vsync(p_enable);
+// Workaround for setting this on thread.
+void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) {
+	DisplayServer::get_singleton()->window_set_vsync_mode(p_mode, p_window);
 }
 }
 
 
 int RendererViewport::get_total_objects_drawn() const {
 int RendererViewport::get_total_objects_drawn() const {

+ 2 - 2
servers/rendering/renderer_viewport.h

@@ -271,8 +271,8 @@ public:
 	int get_total_vertices_drawn() const;
 	int get_total_vertices_drawn() const;
 	int get_total_draw_calls_used() const;
 	int get_total_draw_calls_used() const;
 
 
-	//workaround for setting this on thread
-	void call_set_use_vsync(bool p_enable);
+	// Workaround for setting this on thread.
+	void call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window);
 
 
 	RendererViewport();
 	RendererViewport();
 	virtual ~RendererViewport() {}
 	virtual ~RendererViewport() {}

+ 1 - 1
servers/rendering/rendering_server_default.h

@@ -577,7 +577,7 @@ public:
 	FUNC1RC(float, viewport_get_measured_render_time_cpu, RID)
 	FUNC1RC(float, viewport_get_measured_render_time_cpu, RID)
 	FUNC1RC(float, viewport_get_measured_render_time_gpu, RID)
 	FUNC1RC(float, viewport_get_measured_render_time_gpu, RID)
 
 
-	FUNC1(call_set_use_vsync, bool)
+	FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID)
 
 
 	/* ENVIRONMENT API */
 	/* ENVIRONMENT API */
 
 

+ 1 - 1
servers/rendering_server.h

@@ -1454,7 +1454,7 @@ public:
 
 
 	virtual void set_debug_generate_wireframes(bool p_generate) = 0;
 	virtual void set_debug_generate_wireframes(bool p_generate) = 0;
 
 
-	virtual void call_set_use_vsync(bool p_enable) = 0;
+	virtual void call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) = 0;
 
 
 	virtual bool is_low_end() const = 0;
 	virtual bool is_low_end() const = 0;