From 2626dcbc5f6e6b655e9e28f482c49ae20a24d726 Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 26 Apr 2024 19:42:47 +0800 Subject: [PATCH] fix black screen issue when controlling the second screen on versions that lack multiple display support while using vram decoding (#7836) * avoid create unnecessary video decoder Signed-off-by: 21pages * controlled side uses the most frequent selected codec Signed-off-by: 21pages * fix black screen when control old version's second screen For versions that do not support multiple displays, the display parameter is always 0, need set type of current display Signed-off-by: 21pages --------- Signed-off-by: 21pages --- Cargo.lock | 4 +- .../lib/models/desktop_render_texture.dart | 53 ++++++++++--------- libs/scrap/src/common/codec.rs | 16 ++++-- libs/scrap/src/common/vram.rs | 6 +-- src/client.rs | 43 ++++++++------- 5 files changed, 69 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 881ce84fd..8f8f6f745 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3038,8 +3038,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hwcodec" -version = "0.4.1" -source = "git+https://github.com/21pages/hwcodec#17870c015a3f371339a91c5305d1e920bd8284e3" +version = "0.4.2" +source = "git+https://github.com/21pages/hwcodec#b8ed1e869b3456af6a5f77b7617f861d9a99dcdd" dependencies = [ "bindgen 0.59.2", "cc", diff --git a/flutter/lib/models/desktop_render_texture.dart b/flutter/lib/models/desktop_render_texture.dart index 80477fede..0578bb688 100644 --- a/flutter/lib/models/desktop_render_texture.dart +++ b/flutter/lib/models/desktop_render_texture.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart'; +import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/model.dart'; import 'package:get/get.dart'; @@ -152,40 +153,36 @@ class TextureModel { TextureModel(this.parent); setTextureType({required int display, required bool gpuTexture}) { - debugPrint("setTextureType: display:$display, isGpuTexture:$gpuTexture"); - var texture = _control[display]; - if (texture == null) { - texture = _Control(); - _control[display] = texture; + debugPrint("setTextureType: display=$display, isGpuTexture=$gpuTexture"); + ensureControl(display); + _control[display]?.setTextureType(gpuTexture: gpuTexture); + // For versions that do not support multiple displays, the display parameter is always 0, need set type of current display + final ffi = parent.target; + if (ffi == null) return; + if (!ffi.ffiModel.pi.isSupportMultiDisplay) { + final currentDisplay = CurrentDisplayState.find(ffi.id).value; + if (currentDisplay != display) { + debugPrint( + "setTextureType: currentDisplay=$currentDisplay, isGpuTexture=$gpuTexture"); + ensureControl(currentDisplay); + _control[currentDisplay]?.setTextureType(gpuTexture: gpuTexture); + } } - texture.setTextureType(gpuTexture: gpuTexture); } setRgbaTextureId({required int display, required int id}) { - var ctl = _control[display]; - if (ctl == null) { - ctl = _Control(); - _control[display] = ctl; - } - ctl.setRgbaTextureId(id); + ensureControl(display); + _control[display]?.setRgbaTextureId(id); } setGpuTextureId({required int display, required int id}) { - var ctl = _control[display]; - if (ctl == null) { - ctl = _Control(); - _control[display] = ctl; - } - ctl.setGpuTextureId(id); + ensureControl(display); + _control[display]?.setGpuTextureId(id); } RxInt getTextureId(int display) { - var ctl = _control[display]; - if (ctl == null) { - ctl = _Control(); - _control[display] = ctl; - } - return ctl.textureID; + ensureControl(display); + return _control[display]!.textureID; } updateCurrentDisplay(int curDisplay) { @@ -241,4 +238,12 @@ class TextureModel { await texture.destroy(ffi); } } + + ensureControl(int display) { + var ctl = _control[display]; + if (ctl == null) { + ctl = _Control(); + _control[display] = ctl; + } + } } diff --git a/libs/scrap/src/common/codec.rs b/libs/scrap/src/common/codec.rs index fd283386b..97a444299 100644 --- a/libs/scrap/src/common/codec.rs +++ b/libs/scrap/src/common/codec.rs @@ -221,7 +221,6 @@ impl Encoder { let h265_useable = _all_support_h265_decoding && (h265vram_encoding || h265hw_encoding.is_some()); let mut name = ENCODE_CODEC_NAME.lock().unwrap(); - let mut preference = PreferCodec::Auto; let preferences: Vec<_> = decodings .iter() .filter(|(_, s)| { @@ -233,9 +232,20 @@ impl Encoder { }) .map(|(_, s)| s.prefer) .collect(); - if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) { - preference = preferences[0].enum_value_or(PreferCodec::Auto); + // find the most frequent preference + let mut counts = Vec::new(); + for pref in &preferences { + match counts.iter_mut().find(|(p, _)| p == pref) { + Some((_, count)) => *count += 1, + None => counts.push((pref.clone(), 1)), + } } + let max_count = counts.iter().map(|(_, count)| *count).max().unwrap_or(0); + let (most_frequent, _) = counts + .into_iter() + .find(|(_, count)| *count == max_count) + .unwrap_or((PreferCodec::Auto.into(), 0)); + let preference = most_frequent.enum_value_or(PreferCodec::Auto); #[allow(unused_mut)] let mut auto_codec = CodecName::VP9; diff --git a/libs/scrap/src/common/vram.rs b/libs/scrap/src/common/vram.rs index 157047ec2..fb35ca7f9 100644 --- a/libs/scrap/src/common/vram.rs +++ b/libs/scrap/src/common/vram.rs @@ -24,8 +24,6 @@ use hwcodec::{ }, }; -const OUTPUT_SHARED_HANDLE: bool = false; - // https://www.reddit.com/r/buildapc/comments/d2m4ny/two_graphics_cards_two_monitors/ // https://www.reddit.com/r/techsupport/comments/t2v9u6/dual_monitor_setup_with_dual_gpu/ // https://cybersided.com/two-monitors-two-gpus/ @@ -331,8 +329,8 @@ impl VRamDecoder { } pub fn new(format: CodecFormat, luid: Option) -> ResultType { - log::info!("try create {format:?} vram decoder, luid: {luid:?}"); let ctx = Self::try_get(format, luid).ok_or(anyhow!("Failed to get decode context"))?; + log::info!("try create vram decoder: {ctx:?}"); match Decoder::new(ctx) { Ok(decoder) => Ok(Self { decoder }), Err(_) => { @@ -376,7 +374,7 @@ pub(crate) fn check_available_vram() -> String { gop: MAX_GOP as _, }; let encoders = encode::available(d); - let decoders = decode::available(OUTPUT_SHARED_HANDLE); + let decoders = decode::available(); let available = Available { e: encoders, d: decoders, diff --git a/src/client.rs b/src/client.rs index c765c02cf..c7fe88a79 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1580,7 +1580,10 @@ impl LoginConfigHandler { /// /// * `ignore_default` - If `true`, ignore the default value of the option. fn get_option_message(&self, ignore_default: bool) -> Option { - if self.conn_type.eq(&ConnType::PORT_FORWARD) || self.conn_type.eq(&ConnType::RDP) || self.conn_type.eq(&ConnType::FILE_TRANSFER) { + if self.conn_type.eq(&ConnType::PORT_FORWARD) + || self.conn_type.eq(&ConnType::RDP) + || self.conn_type.eq(&ConnType::FILE_TRANSFER) + { return None; } let mut msg = OptionMessage::new(); @@ -2110,7 +2113,7 @@ where std::thread::spawn(move || { #[cfg(windows)] sync_cpu_usage(); - let mut handler_controller_map = Vec::new(); + let mut handler_controller_map = HashMap::new(); // let mut count = Vec::new(); // let mut duration = std::time::Duration::ZERO; // let mut skip_beginning = Vec::new(); @@ -2141,17 +2144,18 @@ where let display = vf.display as usize; let start = std::time::Instant::now(); let format = CodecFormat::from(&vf); - if handler_controller_map.len() <= display { - for _i in handler_controller_map.len()..=display { - handler_controller_map.push(VideoHandlerController { - handler: VideoHandler::new(format, _i), + if !handler_controller_map.contains_key(&display) { + handler_controller_map.insert( + display, + VideoHandlerController { + handler: VideoHandler::new(format, display), count: 0, duration: std::time::Duration::ZERO, skip_beginning: 0, - }); - } + }, + ); } - if let Some(handler_controller) = handler_controller_map.get_mut(display) { + if let Some(handler_controller) = handler_controller_map.get_mut(&display) { let mut pixelbuffer = true; let mut tmp_chroma = None; match handler_controller.handler.handle_frame( @@ -2219,7 +2223,7 @@ where let mut should_update_supported = false; handler_controller_map .iter() - .map(|h| { + .map(|(_, h)| { if !h.handler.decoder.valid() || h.handler.fail_counter >= MAX_DECODE_FAIL_COUNTER { let mut lc = session.lc.write().unwrap(); let format = h.handler.decoder.format(); @@ -2238,21 +2242,20 @@ where } } MediaData::Reset(display) => { - if let Some(handler_controler) = handler_controller_map.get_mut(display) { + if let Some(handler_controler) = handler_controller_map.get_mut(&display) { handler_controler.handler.reset(None); } } MediaData::RecordScreen(start, display, w, h, id) => { log::info!("record screen command: start: {start}, display: {display}"); - if handler_controller_map.len() == 1 { - // Compatible with the sciter version(single ui session). - // For the sciter version, there're no multi-ui-sessions for one connection. - // The display is always 0, video_handler_controllers.len() is always 1. So we use the first video handler. - handler_controller_map[0] - .handler - .record_screen(start, w, h, id); - } else { - if let Some(handler_controler) = handler_controller_map.get_mut(display) + // Compatible with the sciter version(single ui session). + // For the sciter version, there're no multi-ui-sessions for one connection. + // The display is always 0, video_handler_controllers.len() is always 1. So we use the first video handler. + if let Some(handler_controler) = handler_controller_map.get_mut(&display) { + handler_controler.handler.record_screen(start, w, h, id); + } else if handler_controller_map.len() == 1 { + if let Some(handler_controler) = + handler_controller_map.values_mut().next() { handler_controler.handler.record_screen(start, w, h, id); }