From 92dd0ee1dde39394058075787f38bb32b9c990ba Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:55:03 +0800 Subject: [PATCH] fix: non texture, multi window, switch display (#8353) * fix: non texture, multi window, switch display Signed-off-by: fufesou * fix build Signed-off-by: fufesou --------- Signed-off-by: fufesou --- flutter/lib/common.dart | 3 +- flutter/lib/models/model.dart | 3 +- flutter/lib/web/bridge.dart | 5 +- src/flutter.rs | 92 ++++++++++++++++------------------- src/flutter_ffi.rs | 12 ++--- 5 files changed, 57 insertions(+), 58 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 0e1aca9d0..4536a806d 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2924,7 +2924,8 @@ openMonitorInNewTabOrWindow(int i, String peerId, PeerInfo pi, kMainWindowId, kWindowEventOpenMonitorSession, jsonEncode(args)); } -setNewConnectWindowFrame(int windowId, String peerId, int? display, Rect? screenRect) async { +setNewConnectWindowFrame( + int windowId, String peerId, int? display, Rect? screenRect) async { if (screenRect == null) { await restoreWindowPosition(WindowType.RemoteDesktop, windowId: windowId, display: display, peerId: peerId); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index bfadc3fa5..c7b3debea 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -2420,7 +2420,8 @@ class FFI { 'Unreachable, failed to add existed session to $id, the displays is null while display is $display'); return; } - final addRes = bind.sessionAddExistedSync(id: id, sessionId: sessionId); + final addRes = bind.sessionAddExistedSync( + id: id, sessionId: sessionId, displays: Int32List.fromList(displays)); if (addRes != '') { debugPrint( 'Unreachable, failed to add existed session to $id, $addRes'); diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index fddf14737..60d4aa732 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -59,7 +59,10 @@ class RustdeskImpl { } String sessionAddExistedSync( - {required String id, required UuidValue sessionId, dynamic hint}) { + {required String id, + required UuidValue sessionId, + required Int32List displays, + dynamic hint}) { return ''; } diff --git a/src/flutter.rs b/src/flutter.rs index 79f25430f..5f5065881 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -168,6 +168,9 @@ pub unsafe extern "C" fn get_rustdesk_app_name(buffer: *mut u16, length: i32) -> #[derive(Default)] struct SessionHandler { event_stream: Option>, + // displays of current session. + // We need this variable to check if the display is in use before pushing rgba to flutter. + displays: Vec, renderer: VideoRenderer, } @@ -408,25 +411,6 @@ impl VideoRenderer { } } - fn add_displays(&self, displays: &[i32]) { - let mut sessions_lock = self.map_display_sessions.write().unwrap(); - for display in displays { - let d = *display as usize; - if !sessions_lock.contains_key(&d) { - sessions_lock.insert( - d, - DisplaySessionInfo { - texture_rgba_ptr: 0, - size: (0, 0), - #[cfg(feature = "vram")] - gpu_output_ptr: usize::default(), - notify_render_type: None, - }, - ); - } - } - } - #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn on_rgba(&self, display: usize, rgba: &scrap::ImageRgb) -> bool { let mut write_lock = self.map_display_sessions.write().unwrap(); @@ -598,6 +582,7 @@ impl FlutterHandler { pub fn update_use_texture_render(&self) { self.use_texture_render .store(crate::ui_interface::use_texture_render(), Ordering::Relaxed); + self.display_rgbas.write().unwrap().clear(); } } @@ -1058,26 +1043,39 @@ impl FlutterHandler { } drop(rgba_write_lock); - let is_multi_sessions = self.session_handlers.read().unwrap().len() > 1; + let mut is_sent = false; + let is_multi_sessions = self.is_multi_ui_session(); for h in self.session_handlers.read().unwrap().values() { - // `map_display_sessions` stores the display indices that are used by the video renderer. - let map_display_sessions = h.renderer.map_display_sessions.read().unwrap(); - // The soft renderer does not support multi ui session for now. - if map_display_sessions.len() > 1 { + // The soft renderer does not support multi-displays session for now. + if h.displays.len() > 1 { continue; } // If there're multiple ui sessions, we only notify the ui session that has the display. - // We must make sure that the display is in the `map_display_sessions`. - // `session_start_with_displays()` can guarantee that. if is_multi_sessions { - if !map_display_sessions.contains_key(&display) { + if !h.displays.contains(&display) { continue; } } if let Some(stream) = &h.event_stream { stream.add(EventToUI::Rgba(display)); + is_sent = true; } } + // We need `is_sent` here. Because we use texture render for multi-displays session. + // + // Eg. We have to windows, one is display 1, the other is displays 0&1. + // When image of display 0 is received, we will not send the event. + // + // 1. "display 1" will not send the event. + // 2. "displays 0&1" will not send the event. Because it uses texutre render for now. + if !is_sent { + self.display_rgbas + .write() + .unwrap() + .get_mut(&display) + .unwrap() + .valid = false; + } } #[inline] @@ -1089,8 +1087,7 @@ impl FlutterHandler { rgba: &mut scrap::ImageRgb, ) { for (_, session) in self.session_handlers.read().unwrap().iter() { - if use_texture_render || session.renderer.map_display_sessions.read().unwrap().len() > 1 - { + if use_texture_render || session.displays.len() > 1 { if session.renderer.on_rgba(display, rgba) { if let Some(stream) = &session.event_stream { stream.add(EventToUI::Rgba(display)); @@ -1102,8 +1099,12 @@ impl FlutterHandler { } // This function is only used for the default connection session. -pub fn session_add_existed(peer_id: String, session_id: SessionID) -> ResultType<()> { - sessions::insert_peer_session_id(peer_id, ConnType::DEFAULT_CONN, session_id); +pub fn session_add_existed( + peer_id: String, + session_id: SessionID, + displays: Vec, +) -> ResultType<()> { + sessions::insert_peer_session_id(peer_id, ConnType::DEFAULT_CONN, session_id, displays); Ok(()) } @@ -1523,6 +1524,11 @@ pub fn session_set_size(session_id: SessionID, display: usize, width: usize, hei .unwrap() .get_mut(&session_id) { + // If the session is the first connection, displays is not set yet. + // `displays`` is set while switching displays or adding a new session. + if !h.displays.contains(&display) { + h.displays.push(display); + } h.renderer.set_size(display, width, height); break; } @@ -1562,21 +1568,6 @@ pub fn session_register_gpu_texture(_session_id: SessionID, _display: usize, _ou } } -pub fn session_add_displays(session_id: &SessionID, displays: &[i32]) { - for s in sessions::get_sessions() { - if let Some(h) = s - .ui_handler - .session_handlers - .read() - .unwrap() - .get(session_id) - { - h.renderer.add_displays(displays); - break; - } - } -} - #[inline] #[cfg(not(feature = "vram"))] pub fn get_adapter_luid() -> Option { @@ -1898,8 +1889,9 @@ pub mod sessions { pub fn session_switch_display(is_desktop: bool, session_id: SessionID, value: Vec) { for s in SESSIONS.read().unwrap().values() { - let read_lock = s.ui_handler.session_handlers.read().unwrap(); - if read_lock.contains_key(&session_id) { + let mut write_lock = s.ui_handler.session_handlers.write().unwrap(); + if let Some(h) = write_lock.get_mut(&session_id) { + h.displays = value.iter().map(|x| *x as usize).collect::<_>(); if value.len() == 1 { // Switch display. // This operation will also cause the peer to send a switch display message. @@ -1915,7 +1907,7 @@ pub mod sessions { Some(value[0] as _), &session_id, &s, - &read_lock, + &write_lock, ); } } @@ -1947,9 +1939,11 @@ pub mod sessions { peer_id: String, conn_type: ConnType, session_id: SessionID, + displays: Vec, ) -> bool { if let Some(s) = SESSIONS.read().unwrap().get(&(peer_id, conn_type)) { let mut h = SessionHandler::default(); + h.displays = displays.iter().map(|x| *x as usize).collect::<_>(); #[cfg(not(any(target_os = "android", target_os = "ios")))] let is_support_multi_ui_session = crate::common::is_support_multi_ui_session( &s.ui_handler.peer_info.read().unwrap().version, diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index d6012a04b..4acae7393 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -102,8 +102,12 @@ pub fn peer_get_default_sessions_count(id: String) -> SyncReturn { SyncReturn(sessions::get_session_count(id, ConnType::DEFAULT_CONN)) } -pub fn session_add_existed_sync(id: String, session_id: SessionID) -> SyncReturn { - if let Err(e) = session_add_existed(id.clone(), session_id) { +pub fn session_add_existed_sync( + id: String, + session_id: SessionID, + displays: Vec, +) -> SyncReturn { + if let Err(e) = session_add_existed(id.clone(), session_id, displays) { SyncReturn(format!("Failed to add session with id {}, {}", &id, e)) } else { SyncReturn("".to_owned()) @@ -154,10 +158,6 @@ pub fn session_start_with_displays( ) -> ResultType<()> { session_start_(&session_id, &id, events2ui)?; - // `session_add_displays` is used for software rendering, multi-ui sessions. - // We need to add displays to the session first, then capture the displays. - // Otherwise, the session may not send video frames to the flutter side. - super::flutter::session_add_displays(&session_id, &displays); if let Some(session) = sessions::get_session_by_session_id(&session_id) { session.capture_displays(displays.clone(), vec![], vec![]); for display in displays {