feat: adapt for the latest renderer plugin

This commit is contained in:
Kingtous 2023-02-19 15:25:30 +08:00 committed by fufesou
parent ea07b9690e
commit d3455f3ce2
7 changed files with 85 additions and 24 deletions

View File

@ -19,6 +19,7 @@ import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_hbb/utils/platform_channel.dart'; import 'package:flutter_hbb/utils/platform_channel.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:uni_links_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -44,6 +45,10 @@ var isWeb = false;
var isWebDesktop = false; var isWebDesktop = false;
var version = ""; var version = "";
int androidVersion = 0; int androidVersion = 0;
/// Incriment count for textureId.
int _textureId = 0;
int get newTextureId => _textureId ++;
final textureRenderer = TextureRgbaRenderer();
/// only available for Windows target /// only available for Windows target
int windowsBuildNumber = 0; int windowsBuildNumber = 0;

View File

@ -63,6 +63,8 @@ class _RemotePageState extends State<RemotePage>
late RxBool _zoomCursor; late RxBool _zoomCursor;
late RxBool _remoteCursorMoved; late RxBool _remoteCursorMoved;
late RxBool _keyboardEnabled; late RxBool _keyboardEnabled;
late RxInt _textureId;
late int _textureKey;
final _blockableOverlayState = BlockableOverlayState(); final _blockableOverlayState = BlockableOverlayState();
@ -85,6 +87,8 @@ class _RemotePageState extends State<RemotePage>
_showRemoteCursor = ShowRemoteCursorState.find(id); _showRemoteCursor = ShowRemoteCursorState.find(id);
_keyboardEnabled = KeyboardEnabledState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id);
_remoteCursorMoved = RemoteCursorMovedState.find(id); _remoteCursorMoved = RemoteCursorMovedState.find(id);
_textureKey = newTextureId;
_textureId = RxInt(-1);
} }
void _removeStates(String id) { void _removeStates(String id) {
@ -119,6 +123,16 @@ class _RemotePageState extends State<RemotePage>
if (!Platform.isLinux) { if (!Platform.isLinux) {
Wakelock.enable(); Wakelock.enable();
} }
// Register texture.
_textureId.value = -1;
textureRenderer.createTexture(_textureKey).then((id) async {
if (id != -1) {
final ptr = await textureRenderer.getTexturePtr(_textureKey);
debugPrint("id: $id, texture_key: $_textureKey");
platformFFI.registerTexture(widget.id, ptr);
_textureId.value = id;
}
});
_ffi.ffiModel.updateEventListener(widget.id); _ffi.ffiModel.updateEventListener(widget.id);
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
// Session option should be set after models.dart/FFI.start // Session option should be set after models.dart/FFI.start
@ -198,6 +212,7 @@ class _RemotePageState extends State<RemotePage>
Wakelock.disable(); Wakelock.disable();
} }
Get.delete<FFI>(tag: widget.id); Get.delete<FFI>(tag: widget.id);
textureRenderer.closeTexture(_textureKey);
super.dispose(); super.dispose();
_removeStates(widget.id); _removeStates(widget.id);
} }
@ -346,6 +361,7 @@ class _RemotePageState extends State<RemotePage>
cursorOverImage: _cursorOverImage, cursorOverImage: _cursorOverImage,
keyboardEnabled: _keyboardEnabled, keyboardEnabled: _keyboardEnabled,
remoteCursorMoved: _remoteCursorMoved, remoteCursorMoved: _remoteCursorMoved,
textureId: _textureId,
listenerBuilder: (child) => listenerBuilder: (child) =>
_buildRawPointerMouseRegion(child, enterView, leaveView), _buildRawPointerMouseRegion(child, enterView, leaveView),
); );
@ -383,6 +399,7 @@ class ImagePaint extends StatefulWidget {
final RxBool cursorOverImage; final RxBool cursorOverImage;
final RxBool keyboardEnabled; final RxBool keyboardEnabled;
final RxBool remoteCursorMoved; final RxBool remoteCursorMoved;
final RxInt textureId;
final Widget Function(Widget)? listenerBuilder; final Widget Function(Widget)? listenerBuilder;
ImagePaint( ImagePaint(
@ -392,6 +409,7 @@ class ImagePaint extends StatefulWidget {
required this.cursorOverImage, required this.cursorOverImage,
required this.keyboardEnabled, required this.keyboardEnabled,
required this.remoteCursorMoved, required this.remoteCursorMoved,
required this.textureId,
this.listenerBuilder}) this.listenerBuilder})
: super(key: key); : super(key: key);
@ -466,9 +484,15 @@ class _ImagePaintState extends State<ImagePaint> {
final imageWidth = c.getDisplayWidth() * s; final imageWidth = c.getDisplayWidth() * s;
final imageHeight = c.getDisplayHeight() * s; final imageHeight = c.getDisplayHeight() * s;
final imageSize = Size(imageWidth, imageHeight); final imageSize = Size(imageWidth, imageHeight);
final imageWidget = CustomPaint( print("width: $imageWidth/$imageHeight");
size: imageSize, // final imageWidget = CustomPaint(
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), // size: imageSize,
// painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
// );
final imageWidget = SizedBox(
width: imageHeight,
height: imageHeight,
child: Obx(() => Texture(textureId: widget.textureId.value)),
); );
return NotificationListener<ScrollNotification>( return NotificationListener<ScrollNotification>(
@ -493,9 +517,15 @@ class _ImagePaintState extends State<ImagePaint> {
context, _buildListener(imageWidget), c.size, imageSize)), context, _buildListener(imageWidget), c.size, imageSize)),
)); ));
} else { } else {
final imageWidget = CustomPaint( // final imageWidget = CustomPaint(
size: Size(c.size.width, c.size.height), // size: Size(c.size.width, c.size.height),
painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), // painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s),
// );
final imageWidget = Center(
child: AspectRatio(
aspectRatio: c.size.width / c.size.height,
child: Obx(() => Texture(textureId: widget.textureId.value)),
),
); );
return mouseRegion(child: _buildListener(imageWidget)); return mouseRegion(child: _buildListener(imageWidget));
} }

View File

@ -1446,14 +1446,15 @@ class FFI {
} }
} else if (message is EventToUI_Rgba) { } else if (message is EventToUI_Rgba) {
// Fetch the image buffer from rust codes. // Fetch the image buffer from rust codes.
final sz = platformFFI.getRgbaSize(id); // final sz = platformFFI.getRgbaSize(id);
if (sz == null || sz == 0) { // if (sz == null || sz == 0) {
return; // return;
} // }
final rgba = platformFFI.getRgba(id, sz); // final rgba = platformFFI.getRgba(id, sz);
if (rgba != null) { // if (rgba != null) {
imageModel.onRgba(rgba); // imageModel.onRgba(rgba);
} // }
// imageModel.onRgba(rgba);
} }
} }
debugPrint('Exit session event loop'); debugPrint('Exit session event loop');

View File

@ -30,6 +30,9 @@ typedef F4Dart = int Function(Pointer<Utf8>);
typedef F5 = Void Function(Pointer<Utf8>); typedef F5 = Void Function(Pointer<Utf8>);
typedef F5Dart = void Function(Pointer<Utf8>); typedef F5Dart = void Function(Pointer<Utf8>);
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt); typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
// pub fn session_register_texture(id: *const char, ptr: usize)
typedef F6 = Void Function(Pointer<Utf8>, Uint64);
typedef F6Dart = void Function(Pointer<Utf8>, int);
/// FFI wrapper around the native Rust core. /// FFI wrapper around the native Rust core.
/// Hides the platform differences. /// Hides the platform differences.
@ -52,6 +55,8 @@ class PlatformFFI {
F3? _session_get_rgba; F3? _session_get_rgba;
F4Dart? _session_get_rgba_size; F4Dart? _session_get_rgba_size;
F5Dart? _session_next_rgba; F5Dart? _session_next_rgba;
F6Dart? _session_register_texture;
static get localeName => Platform.localeName; static get localeName => Platform.localeName;
@ -130,6 +135,13 @@ class PlatformFFI {
malloc.free(a); malloc.free(a);
} }
void registerTexture(String id, int ptr) {
if (_session_register_texture == null) return;
final a = id.toNativeUtf8();
_session_register_texture!(a, ptr);
malloc.free(a);
}
/// Init the FFI class, loads the native Rust core library. /// Init the FFI class, loads the native Rust core library.
Future<void> init(String appType) async { Future<void> init(String appType) async {
_appType = appType; _appType = appType;
@ -150,6 +162,7 @@ class PlatformFFI {
dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size"); dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size");
_session_next_rgba = _session_next_rgba =
dylib.lookupFunction<F5, F5Dart>("session_next_rgba"); dylib.lookupFunction<F5, F5Dart>("session_next_rgba");
_session_register_texture = dylib.lookupFunction<F6, F6Dart>("session_register_texture");
try { try {
// SYSTEM user failed // SYSTEM user failed
_dir = (await getApplicationDocumentsDirectory()).path; _dir = (await getApplicationDocumentsDirectory()).path;

View File

@ -8,7 +8,7 @@ use hbb_common::{
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType, bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType,
ResultType, ResultType,
}; };
use libc::c_void; use libc::{c_void};
use libloading::{Library, Symbol}; use libloading::{Library, Symbol};
use serde_json::json; use serde_json::json;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -37,7 +37,7 @@ lazy_static::lazy_static! {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
let lib = Library::new("texture_rgba_renderer_plugin.dylib"); let lib = Library::new("texture_rgba_renderer_plugin.dylib");
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
let lib = Library::new("texture_rgba_renderer_plugin.so"); let lib = Library::new("libtexture_rgba_renderer_plugin.so");
lib.expect("`libtexture_rgba_renderer_plugin` not found, please add `texture_rgba_renderer` in your flutter project") lib.expect("`libtexture_rgba_renderer_plugin` not found, please add `texture_rgba_renderer` in your flutter project")
} }
}; };
@ -129,7 +129,8 @@ pub struct FlutterHandler {
// We must check the `rgba_valid` before reading [rgba]. // We must check the `rgba_valid` before reading [rgba].
pub rgba: Arc<RwLock<Vec<u8>>>, pub rgba: Arc<RwLock<Vec<u8>>>,
pub rgba_valid: Arc<AtomicBool>, pub rgba_valid: Arc<AtomicBool>,
pub renderer: VideoRenderer, pub renderer: Arc<RwLock<VideoRenderer>>,
peer_info: Arc<RwLock<PeerInfo>>
} }
pub type FlutterRgbaRendererPluginOnRgba = pub type FlutterRgbaRendererPluginOnRgba =
unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int); unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int);
@ -148,10 +149,12 @@ impl Default for VideoRenderer {
fn default() -> Self { fn default() -> Self {
unsafe { unsafe {
Self { Self {
ptr: 0,
width: 0,
height: 0,
on_rgba_func: TEXURE_RGBA_RENDERER_PLUGIN on_rgba_func: TEXURE_RGBA_RENDERER_PLUGIN
.get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba") .get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba")
.expect("Symbol FlutterRgbaRendererPluginOnRgba not found."), .expect("Symbol FlutterRgbaRendererPluginOnRgba not found."),
..Default::default()
} }
} }
} }
@ -220,7 +223,7 @@ impl FlutterHandler {
} }
pub fn register_texture(&mut self, ptr: usize) { pub fn register_texture(&mut self, ptr: usize) {
self.renderer.ptr = ptr; self.renderer.write().unwrap().ptr = ptr;
} }
} }
@ -381,6 +384,7 @@ impl InvokeUiSession for FlutterHandler {
// unused in flutter // unused in flutter
fn adapt_size(&self) {} fn adapt_size(&self) {}
#[inline]
fn on_rgba(&self, data: &mut Vec<u8>) { fn on_rgba(&self, data: &mut Vec<u8>) {
// If the current rgba is not fetched by flutter, i.e., is valid. // If the current rgba is not fetched by flutter, i.e., is valid.
// We give up sending a new event to flutter. // We give up sending a new event to flutter.
@ -390,13 +394,15 @@ impl InvokeUiSession for FlutterHandler {
self.rgba_valid.store(true, Ordering::Relaxed); self.rgba_valid.store(true, Ordering::Relaxed);
// Return the rgba buffer to the video handler for reusing allocated rgba buffer. // Return the rgba buffer to the video handler for reusing allocated rgba buffer.
std::mem::swap::<Vec<u8>>(data, &mut *self.rgba.write().unwrap()); std::mem::swap::<Vec<u8>>(data, &mut *self.rgba.write().unwrap());
#[cfg(any(target_os = "android", target_os = "ios"))]
if let Some(stream) = &*self.event_stream.read().unwrap() { if let Some(stream) = &*self.event_stream.read().unwrap() {
stream.add(EventToUI::Rgba); stream.add(EventToUI::Rgba);
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
self.renderer {
self.renderer.read().unwrap()
.on_rgba(self.rgba.read().unwrap().as_ptr()); .on_rgba(self.rgba.read().unwrap().as_ptr());
self.next_rgba();
}
} }
fn set_peer_info(&self, pi: &PeerInfo) { fn set_peer_info(&self, pi: &PeerInfo) {
@ -410,6 +416,9 @@ impl InvokeUiSession for FlutterHandler {
features.insert("privacy_mode", 0); features.insert("privacy_mode", 0);
} }
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned()); let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
*self.peer_info.write().unwrap() = pi.clone();
let curr_display = &pi.displays[pi.current_display as usize];
self.renderer.write().unwrap().set_size(curr_display.width, curr_display.height);
self.push_event( self.push_event(
"peer_info", "peer_info",
vec![ vec![
@ -426,6 +435,7 @@ impl InvokeUiSession for FlutterHandler {
} }
fn set_displays(&self, displays: &Vec<DisplayInfo>) { fn set_displays(&self, displays: &Vec<DisplayInfo>) {
self.peer_info.write().unwrap().displays = displays.clone();
self.push_event( self.push_event(
"sync_peer_info", "sync_peer_info",
vec![("displays", &Self::make_displays_msg(displays))], vec![("displays", &Self::make_displays_msg(displays))],
@ -457,6 +467,8 @@ impl InvokeUiSession for FlutterHandler {
} }
fn switch_display(&self, display: &SwitchDisplay) { fn switch_display(&self, display: &SwitchDisplay) {
let curr_display = &self.peer_info.read().unwrap().displays[display.display as usize];
self.renderer.write().unwrap().set_size(curr_display.width, curr_display.height);
self.push_event( self.push_event(
"switch_display", "switch_display",
vec![ vec![
@ -521,7 +533,7 @@ impl InvokeUiSession for FlutterHandler {
} }
#[inline] #[inline]
fn next_rgba(&mut self) { fn next_rgba(&self) {
self.rgba_valid.store(false, Ordering::Relaxed); self.rgba_valid.store(false, Ordering::Relaxed);
} }
} }

View File

@ -298,7 +298,7 @@ impl InvokeUiSession for SciterHandler {
std::ptr::null() std::ptr::null()
} }
fn next_rgba(&mut self) {} fn next_rgba(&self) {}
} }
pub struct SciterSession(Session<SciterHandler>); pub struct SciterSession(Session<SciterHandler>);

View File

@ -798,7 +798,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn on_voice_call_waiting(&self); fn on_voice_call_waiting(&self);
fn on_voice_call_incoming(&self); fn on_voice_call_incoming(&self);
fn get_rgba(&self) -> *const u8; fn get_rgba(&self) -> *const u8;
fn next_rgba(&mut self); fn next_rgba(&self);
} }
impl<T: InvokeUiSession> Deref for Session<T> { impl<T: InvokeUiSession> Deref for Session<T> {