소스 검색

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

Hugo Locurcio 4 년 전
부모
커밋
a2d5f191d8
41개의 변경된 파일310개의 추가작업 그리고 257개의 파일을 삭제
  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.
 	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");
 	GLOBAL_DEF("physics/2d/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;
 	bool _allow_hidpi = false;
 	bool _allow_layered = false;
-	bool _use_vsync;
-	bool _vsync_via_compositor;
 	bool _stdout_enabled = true;
 	bool _stderr_enabled = true;
 

+ 39 - 30
doc/classes/DisplayServer.xml

@@ -44,9 +44,11 @@
 			</return>
 			<argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode">
 			</argument>
-			<argument index="1" name="flags" type="int">
+			<argument index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode">
 			</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>
 			<description>
 			</description>
@@ -671,34 +673,6 @@
 				[b]Note:[/b] This method is implemented on Android, iOS and UWP.
 			</description>
 		</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">
 			<return type="void">
 			</return>
@@ -791,6 +765,15 @@
 			<description>
 			</description>
 		</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">
 			<return type="void">
 			</return>
@@ -995,6 +978,19 @@
 			<description>
 			</description>
 		</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">
 			<return type="void">
 			</return>
@@ -1151,5 +1147,18 @@
 		</constant>
 		<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
 		</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>
 </class>

+ 5 - 7
doc/classes/ProjectSettings.xml

@@ -445,7 +445,7 @@
 		</member>
 		<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.
-			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.
 		</member>
 		<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">
 			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 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 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.

+ 46 - 10
drivers/vulkan/vulkan_context.cpp

@@ -1189,7 +1189,7 @@ bool VulkanContext::_use_validation_layers() {
 	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);
 
 	if (!queues_initialized) {
@@ -1217,6 +1217,7 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfa
 	window.surface = p_surface;
 	window.width = p_width;
 	window.height = p_height;
+	window.vsync_mode = p_vsync_mode;
 	Error err = _update_swap_chain(&window);
 	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
 	// 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
 	//  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
 	// 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);
-	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.
 	// Application desires to acquire 3 images at a time for triple
@@ -1455,7 +1480,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
 		/*pQueueFamilyIndices*/ nullptr,
 		/*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
 		/*compositeAlpha*/ compositeAlpha,
-		/*presentMode*/ swapchainPresentMode,
+		/*presentMode*/ window->presentMode,
 		/*clipped*/ true,
 		/*oldSwapchain*/ VK_NULL_HANDLE,
 	};
@@ -2162,6 +2187,17 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
 	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() {
 	command_buffer_queue.resize(1); // First one is always the setup command.
 	command_buffer_queue.write[0] = nullptr;

+ 5 - 1
drivers/vulkan/vulkan_context.h

@@ -124,6 +124,7 @@ private:
 		uint32_t current_buffer = 0;
 		int width = 0;
 		int height = 0;
+		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
 		VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
 		VkRenderPass render_pass = VK_NULL_HANDLE;
 	};
@@ -222,7 +223,7 @@ private:
 protected:
 	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();
 
@@ -276,6 +277,9 @@ public:
 	String get_device_name() 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();
 	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::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
+static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED;
 static uint32_t window_flags = 0;
 static Size2i window_size = Size2i(1024, 600);
-static bool window_vsync_via_compositor = false;
 
 static int init_screen = -1;
 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("  --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("  --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("  --tablet-driver                              Pen tablet input driver.\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;
 	bool use_custom_res = true;
 	bool force_res = false;
-	bool saw_vsync_via_compositor_override = false;
 #ifdef TOOLS_ENABLED
 	bool found_project = false;
 #endif
-	bool use_vsync = false;
 
 	packed_data = PackedData::get_singleton();
 	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)
 
 			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
 		} 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);
 	}
 
-	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
     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);
@@ -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)));
 	}
-
+	{
+		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));
 	ProjectSettings::get_singleton()->set_custom_property_info("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
 
 		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) {
 			//ok i guess we can't use this display server, try other ones
 			for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
 				if (i == display_driver_idx) {
 					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) {
 					break;
 				}

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

@@ -85,12 +85,6 @@ Force low\-DPI mode (macOS and Windows only).
 .TP
 \fB\-\-no\-window\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:"
 .TP
 \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' \
   '--low-dpi[force low-DPI mode (macOS and Windows only)]' \
   '--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)]' \
   '(-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]' \

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

@@ -54,8 +54,6 @@ _complete_godot_options() {
 --position
 --low-dpi
 --no-window
---enable-vsync-via-compositor
---disable-vsync-via-compositor
 --debug
 --breakpoints
 --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 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 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:
 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;
 }
 
-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) {
 		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(!context_vulkan);
+		VSyncMode last_vsync_mode = context_vulkan->get_vsync_mode(MAIN_WINDOW_ID);
 		context_vulkan->window_destroy(MAIN_WINDOW_ID);
 
 		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);
 			context_vulkan = nullptr;
 			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);
 }
 
-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;
 
 	// 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();
-		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);
 			context_vulkan = nullptr;
 			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 {
 	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 bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) 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);
 
@@ -211,7 +213,7 @@ public:
 	void mouse_set_mode(MouseMode p_mode);
 	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 void register_android_driver();
 
@@ -221,7 +223,7 @@ public:
 	virtual Point2i mouse_get_position() 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();
 };
 

+ 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;
 }
 
-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;
 	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
 	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));
 	}
 
-	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() {

+ 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;
 
 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() 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);
 
-	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();
 
 public:
@@ -76,7 +76,7 @@ public:
 	static DisplayServerIPhone *get_singleton();
 
 	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();
 
 	// MARK: - Events
@@ -176,6 +176,9 @@ public:
 
 	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 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();
 }
 
-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;
 
 #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();
-		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);
 			context_vulkan = nullptr;
 			ERR_FAIL_MSG("Failed to create Vulkan window.");
@@ -147,8 +147,8 @@ DisplayServerIPhone::~DisplayServerIPhone() {
 #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() {
@@ -581,3 +581,19 @@ void DisplayServerIPhone::resize_window(CGSize viewSize) {
 	Variant resize_rect = Rect2i(Point2i(), size);
 	_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;
 
 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();

+ 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;
 }
 
-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;
 	createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.pNext = nullptr;
@@ -47,7 +47,7 @@ Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CA
 			vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 	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() {}

+ 24 - 8
platform/linuxbsd/display_server_x11.cpp

@@ -855,10 +855,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
 	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_
 
-	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++) {
 		if (p_flags & (1 << i)) {
 			window_set_flag(WindowFlags(i), true, id);
@@ -3641,6 +3641,22 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
 	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> drivers;
 
@@ -3654,8 +3670,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
 	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) {
 		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.",
@@ -3664,7 +3680,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
 	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
 
 	long visualMask = VisualScreenMask;
@@ -3828,7 +3844,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 
 #if defined(VULKAN_ENABLED)
 		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");
 		}
 #endif
@@ -3865,7 +3881,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 	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);
 
 	r_error = OK;
@@ -4101,7 +4117,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	Point2i window_position(
 			(screen_get_size(0).width - p_resolution.width) / 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) {
 		r_error = ERR_CANT_CREATE;
 		return;

+ 7 - 4
platform/linuxbsd/display_server_x11.h

@@ -152,7 +152,7 @@ class DisplayServerX11 : public DisplayServer {
 	Map<WindowID, WindowData> windows;
 
 	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;
 	Window xdnd_source_window;
@@ -307,7 +307,7 @@ public:
 
 	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 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_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 CursorShape cursor_get_shape() const;
 	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_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 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();
 };
 

+ 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;
 }
 
-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;
 	createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
 	createInfo.pNext = nullptr;
@@ -46,7 +46,7 @@ Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Win
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	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() {

+ 1 - 1
platform/linuxbsd/vulkan_context_x11.h

@@ -38,7 +38,7 @@ class VulkanContextX11 : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 
 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();

+ 7 - 4
platform/osx/display_server_osx.h

@@ -145,7 +145,7 @@ public:
 
 	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 _send_window_event(const WindowData &wd, WindowEvent 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 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 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 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 String ime_get_text() const override;
 
@@ -314,12 +317,12 @@ public:
 	virtual void console_set_visible(bool p_enabled) 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 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();
 };
 

+ 24 - 8
platform/osx/display_server_osx.mm

@@ -2388,10 +2388,10 @@ Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
 	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_
 
-	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++) {
 		if (p_flags & (1 << i)) {
 			window_set_flag(WindowFlags(i), true, id);
@@ -3546,6 +3546,22 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
 	[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> drivers;
 
@@ -3596,15 +3612,15 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co
 	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) {
 		ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
 	}
 	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;
 	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 (rendering_driver == "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");
 			}
 		}
@@ -3750,7 +3766,7 @@ bool DisplayServerOSX::is_console_visible() const {
 	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);
 
 	r_error = OK;
@@ -3886,7 +3902,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 	Point2i window_position(
 			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);
-	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);
 	for (int i = 0; i < WINDOW_FLAG_MAX; 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;
 
 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();

+ 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;
 }
 
-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;
 	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
 	createInfo.pNext = nullptr;
@@ -45,7 +45,7 @@ Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
 	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() {

+ 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;
 }
 
-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() {
 	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) {
-	vsync_via_compositor = p_use && should_vsync_via_compositor();
-
 	if (wglSwapIntervalEXT) {
-		int swap_interval = (p_use && !vsync_via_compositor) ? 1 : 0;
+		int swap_interval = p_use ? 1 : 0;
 		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;
 	hWnd = hwnd;
 	use_vsync = false;
-	vsync_via_compositor = false;
 	pixel_format = 0;
 }
 

+ 0 - 3
platform/windows/context_gl_windows.h

@@ -50,13 +50,10 @@ class ContextGL_Windows {
 	HWND hWnd;
 	bool opengl_3_context;
 	bool use_vsync;
-	bool vsync_via_compositor;
 
 	PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
 	PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
 
-	static bool should_vsync_via_compositor();
-
 public:
 	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;
 }
 
-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_
 
-	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.");
 
 	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);
 }
 
-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) {
@@ -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 dwStyle;
 
@@ -3030,7 +3039,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 #ifdef VULKAN_ENABLED
 
 		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);
 				context_vulkan = nullptr;
 				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;
 	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);
-		set_vsync_via_compositor(video_mode.vsync_via_compositor);
 
 		if (RasterizerGLES2::is_viable() == OK) {
 			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).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.");
 
 	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
@@ -3347,8 +3355,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
 	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) {
 		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.",

+ 7 - 7
platform/windows/display_server_windows.h

@@ -389,7 +389,7 @@ class DisplayServerWindows : public DisplayServer {
 
 	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;
 	Map<WindowID, WindowData> windows;
 
@@ -469,7 +469,7 @@ public:
 
 	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 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_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 bool is_console_visible() const;
 
@@ -558,16 +561,13 @@ public:
 	virtual void set_native_icon(const String &p_filename);
 	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);
 
-	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 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();
 };
 

+ 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;
 }
 
-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;
 	createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
 	createInfo.pNext = nullptr;
 	createInfo.flags = 0;
 	createInfo.hinstance = p_instance;
 	createInfo.hwnd = p_window;
-
 	VkSurfaceKHR surface;
 	VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
 	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() {

+ 1 - 1
platform/windows/vulkan_context_win.h

@@ -38,7 +38,7 @@ class VulkanContextWindows : public VulkanContext {
 	virtual const char *_get_platform_surface_extension() const;
 
 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();

+ 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);
 	DisplayServer::get_singleton()->window_set_current_screen(current_screen, 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"
 
 DisplayServer *DisplayServer::singleton = nullptr;
-DisplayServer::SwitchVSyncCallbackInThread DisplayServer::switch_vsync_function = nullptr;
 
 bool DisplayServer::hidpi_allowed = false;
 
@@ -185,7 +184,7 @@ bool DisplayServer::screen_is_kept_on() const {
 	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.");
 }
 
@@ -309,29 +308,13 @@ void DisplayServer::set_icon(const Ref<Image> &p_icon) {
 	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) {
@@ -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_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("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_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_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("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_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_GO_BACK_REQUEST);
 	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) {
@@ -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();
 }
 
-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);
-	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) {

+ 14 - 17
servers/display_server.h

@@ -42,7 +42,6 @@ class DisplayServer : public Object {
 	GDCLASS(DisplayServer, Object)
 
 	static DisplayServer *singleton;
-	bool vsync_enabled = true;
 	static bool hidpi_allowed;
 
 public:
@@ -57,7 +56,14 @@ public:
 		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)();
 
 private:
@@ -84,7 +90,6 @@ protected:
 	static int server_create_count;
 
 	friend class RendererViewport;
-	virtual void _set_use_vsync(bool p_enable);
 
 public:
 	enum Feature {
@@ -221,7 +226,7 @@ public:
 		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 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 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 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_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 {
 		CONTEXT_EDITOR,
 		CONTEXT_PROJECTMAN,
@@ -376,7 +372,7 @@ public:
 	static int get_create_function_count();
 	static const char *get_create_function_name(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();
@@ -389,5 +385,6 @@ VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation)
 VARIANT_ENUM_CAST(DisplayServer::WindowMode)
 VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
 VARIANT_ENUM_CAST(DisplayServer::CursorShape)
+VARIANT_ENUM_CAST(DisplayServer::VSyncMode)
 
 #endif // DISPLAY_SERVER_H

+ 1 - 1
servers/display_server_headless.h

@@ -45,7 +45,7 @@ private:
 		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;
 		RasterizerDummy::make_current();
 		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);
 }
 
-//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 {

+ 2 - 2
servers/rendering/renderer_viewport.h

@@ -271,8 +271,8 @@ public:
 	int get_total_vertices_drawn() 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();
 	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_gpu, RID)
 
-	FUNC1(call_set_use_vsync, bool)
+	FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID)
 
 	/* 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 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;