Repository: godotengine/godot (language: cpp)

Issue:
Horrible Flickering when closing docks while embedded game is paused
### Tested versions

- Reproducible in Godot 4.4 beta1

### System information

🪟 Windows 11 - 🤖 Godot 4.4 beta1

### Issue description

Closing a dock while the game is paused and embedded causes the screen to flicker pretty badly.

⚠️ Photosensitivity warning ⚠️
🎥 See screen recording:

https://github.com/user-attachments/assets/4cb0c17c-bc7b-4723-9e30-91b3ea54bf1f

### Steps to reproduce

Enable 'Embed Game on Next Play' in the Game tab.

1. Run a game.
2. Open a dock.
3. Pause the game. 
4. Close the dock.
5. Survive the flickering ⚠️🔦📸💥😵‍💫😵‍💫😵‍💫

### Minimal reproduction project (MRP)

N/A


Discussion / hints:
Thanks for reporting the issue.

I'm unfortunately not able to reproduce on my computer on Windows 11 with 4.4 Beta 1 or with the current master version.

Can you give us a little more information:
- Are you using the Pause button on the right or the Suspend button on the left? Does the same issue happens in both pause mode?
![Image](https://github.com/user-attachments/assets/58a087e7-06b7-406f-9b89-1572191525ad)

- Does the same flickering happens when you resize the dock area or the left or right dock while the game is paused?
- Does the flickering happens in an empty project. If not, can you give us a MRP that reproduce the error?
- Can you give us more details on your graphic card model?
- Are you in Compatibility mode or Forward+?

I assume it's the pause button, the one in the right corner, because I couldn't detect any other visual artifacts
https://github.com/user-attachments/assets/1acc2be0-b8ca-43d7-8bc2-b89d88357829
I still can't reproduce. It's weird that the embedded causes that. It seems a problem where Godot does not rerender in some situation because it's paused. Do you have the same artefacts if running not embedded, pause the game and try to resize the game window?
I'm able to reproduce, but only in the Floating Window, not in embedded in the editor. Fun fact, the actefact are present for me even when not embedded at all. I guess this bug was there before the embedding but it was not very problematic because nobody tries to resize the game window while it's paused usually.

https://github.com/user-attachments/assets/ed6b2f91-a3aa-49fa-a723-24c144949a33
Can confirm it only happens with the top right pause button.
The dock has to be open before pausing. If the dock opens because of the pause action, the game properly resizes and there's no flickering.
The game size not updating while paused is somewhat expected, but the the flickering (when embedded) seems very undesireable.

Sorry, should've mentioned I'm on Compatability backend with an AMD Ryzen 6800U.

Hmmmm... wasn't able to get it to flicker in a fresh project. Neither on Forward+ nor Compatability... Might have something to do with redraws in my project. Tho I don't think I'm doing anything crazy there.
Thanks for the info. It's definitively something with the redraw, but I don't think it's really some specific to your project. I think it will be difficult to fix Godot to force the rerender when the game is paused. I'm working on a workaround to hide the game and display a message when the game is embedded, paused and resized.

Fix patch:
diff --git a/editor/plugins/game_view_plugin.cpp b/editor/plugins/game_view_plugin.cpp
index 723c762a72a5..ad501e77a6d8 100644
--- a/editor/plugins/game_view_plugin.cpp
+++ b/editor/plugins/game_view_plugin.cpp
@@ -301,6 +301,7 @@ void GameView::_stop_pressed() {
 	}
 
 	_detach_script_debugger();
+	paused = false;
 
 	EditorNode::get_singleton()->set_unfocused_low_processor_usage_mode_enabled(true);
 	embedded_process->reset();
@@ -515,15 +516,26 @@ void GameView::_update_embed_menu_options() {
 }
 
 void GameView::_update_embed_window_size() {
-	if (embed_size_mode == SIZE_MODE_FIXED || embed_size_mode == SIZE_MODE_KEEP_ASPECT) {
-		//The embedded process control will need the desired window size.
-		EditorRun::WindowPlacement placement = EditorRun::get_window_placement();
-		embedded_process->set_window_size(placement.size);
+	if (paused) {
+		// When paused, Godot does not re-render. As a result, resizing the game window to a larger size
+		// causes artifacts and flickering. However, resizing to a smaller size seems fine.
+		// To prevent artifacts and flickering, we will force the game window to maintain its size.
+		// Using the same technique as SIZE_MODE_FIXED, the embedded process control will
+		// prevent resizing the game to a larger size while maintaining the aspect ratio.
+		embedded_process->set_window_size(size_paused);
+		embedded_process->set_keep_aspect(false);
+
 	} else {
-		//Stretch... No need for the window size.
-		embedded_process->set_window_size(Size2i());
+		if (embed_size_mode == SIZE_MODE_FIXED || embed_size_mode == SIZE_MODE_KEEP_ASPECT) {
+			// The embedded process control will need the desired window size.
+			EditorRun::WindowPlacement placement = EditorRun::get_window_placement();
+			embedded_process->set_window_size(placement.size);
+		} else {
+			// Stretch... No need for the window size.
+			embedded_process->set_window_size(Size2i());
+		}
+		embedded_process->set_keep_aspect(embed_size_mode == SIZE_MODE_KEEP_ASPECT);
 	}
-	embedded_process->set_keep_aspect(embed_size_mode == SIZE_MODE_KEEP_ASPECT);
 }
 
 void GameView::_hide_selection_toggled(bool p_pressed) {
@@ -787,7 +799,8 @@ void GameView::_window_close_request() {
 		embedded_process->reset();
 
 		// When the embedding is not complete, we need to kill the process.
-		if (embedded_process->is_embedding_in_progress()) {
+		// If the game is paused, the close request will not be processed by the game, so it's better to kill the process.
+		if (paused || embedded_process->is_embedding_in_progress()) {
 			// Call deferred to prevent the _stop_pressed callback to be executed before the wrapper window
 			// actually closes.
 			callable_mp(EditorRunBar::get_singleton(), &EditorRunBar::stop_playing).call_deferred();
@@ -795,6 +808,20 @@ void GameView::_window_close_request() {
 	}
 }
 
+void GameView::_debugger_breaked(bool p_breaked, bool p_can_debug) {
+	if (p_breaked == paused) {
+		return;
+	}
+
+	paused = p_breaked;
+
+	if (paused) {
+		size_paused = embedded_process->get_screen_embedded_window_rect().size;
+	}
+
+	_update_embed_window_size();
+}
+
 GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
 	singleton = this;
 
@@ -984,6 +1011,8 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
 	p_wrapper->set_override_close_request(true);
 	p_wrapper->connect("window_close_requested", callable_mp(this, &GameView::_window_close_request));
 	p_wrapper->connect("window_size_changed", callable_mp(this, &GameView::_update_floating_window_settings));
+
+	EditorDebuggerNode::get_singleton()->connect("breaked", callable_mp(this, &GameView::_debugger_breaked));
 }
 
 ///////
@@ -1053,15 +1082,18 @@ void GameViewPlugin::_window_visibility_changed(bool p_visible) {
 }
 
 void GameViewPlugin::_save_last_editor(const String &p_editor) {
-	if (p_editor != get_name()) {
+	if (p_editor != get_plugin_name()) {
 		last_editor = p_editor;
 	}
 }
 
 void GameViewPlugin::_focus_another_editor() {
 	if (window_wrapper->get_window_enabled()) {
-		ERR_FAIL_COND(last_editor.is_empty());
-		EditorInterface::get_singleton()->set_main_screen_editor(last_editor);
+		if (last_editor.is_empty()) {
+			EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_2D);
+		} else {
+			EditorInterface::get_singleton()->set_main_screen_editor(last_editor);
+		}
 	}
 }
 
diff --git a/editor/plugins/game_view_plugin.h b/editor/plugins/game_view_plugin.h
index 7402b270e3c0..dd384280b5fb 100644
--- a/editor/plugins/game_view_plugin.h
+++ b/editor/plugins/game_view_plugin.h
@@ -122,6 +122,8 @@ class GameView : public VBoxContainer {
 	bool embed_on_play = true;
 	bool make_floating_on_play = true;
 	EmbedSizeMode embed_size_mode = SIZE_MODE_FIXED;
+	bool paused = false;
+	Size2 size_paused;
 
 	Rect2i floating_window_rect;
 	int floating_window_screen = -1;
@@ -186,6 +188,8 @@ class GameView : public VBoxContainer {
 	void _detach_script_debugger();
 	void _remote_window_title_changed(String title);
 
+	void _debugger_breaked(bool p_breaked, bool p_can_debug);
+
 protected:
 	void _notification(int p_what);
 


Test patch: