From 72ec86b58d63e2e3fe63480b5307028ba75c72f1 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Tue, 28 May 2024 16:42:30 +0800 Subject: [PATCH] refact: texture render as an option (#8168) * refact: texture render as an option Signed-off-by: fufesou * refact: texture render, translation Signed-off-by: fufesou * refact: texture render as option Signed-off-by: fufesou * Update ui_interface.rs --------- Signed-off-by: fufesou Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com> --- .github/workflows/flutter-build.yml | 7 +- Cargo.toml | 1 - build.py | 4 - flutter/lib/common.dart | 6 - .../lib/common/widgets/setting_widgets.dart | 8 +- flutter/lib/common/widgets/toolbar.dart | 7 +- flutter/lib/consts.dart | 3 + .../desktop/pages/desktop_setting_page.dart | 71 +++-- flutter/lib/desktop/pages/remote_page.dart | 6 +- .../lib/desktop/widgets/remote_toolbar.dart | 40 ++- .../lib/models/desktop_render_texture.dart | 35 +-- flutter/lib/models/model.dart | 38 ++- flutter/lib/web/bridge.dart | 8 +- libs/hbb_common/src/config.rs | 2 + libs/scrap/src/common/codec.rs | 4 +- libs/scrap/src/common/mod.rs | 5 + src/client.rs | 61 ++-- src/client/io_loop.rs | 5 +- src/common.rs | 25 +- src/flutter.rs | 278 +++++++++--------- src/flutter_ffi.rs | 30 +- src/lang/ar.rs | 2 + src/lang/bg.rs | 2 + src/lang/ca.rs | 2 + src/lang/cn.rs | 2 + src/lang/cs.rs | 2 + src/lang/da.rs | 2 + src/lang/de.rs | 2 + src/lang/el.rs | 2 + src/lang/en.rs | 1 + src/lang/eo.rs | 2 + src/lang/es.rs | 2 + src/lang/et.rs | 2 + src/lang/fa.rs | 2 + src/lang/fr.rs | 2 + src/lang/he.rs | 2 + src/lang/hr.rs | 2 + src/lang/hu.rs | 2 + src/lang/id.rs | 2 + src/lang/it.rs | 2 + src/lang/ja.rs | 2 + src/lang/ko.rs | 2 + src/lang/kz.rs | 2 + src/lang/lt.rs | 2 + src/lang/lv.rs | 2 + src/lang/nb.rs | 2 + src/lang/nl.rs | 2 + src/lang/pl.rs | 2 + src/lang/pt_PT.rs | 2 + src/lang/ptbr.rs | 2 + src/lang/ro.rs | 2 + src/lang/ru.rs | 2 + src/lang/sk.rs | 2 + src/lang/sl.rs | 2 + src/lang/sq.rs | 2 + src/lang/sr.rs | 2 + src/lang/sv.rs | 2 + src/lang/template.rs | 2 + src/lang/th.rs | 2 + src/lang/tr.rs | 2 + src/lang/tw.rs | 2 + src/lang/ua.rs | 2 + src/lang/vn.rs | 2 + src/server/video_service.rs | 2 +- src/ui_interface.rs | 23 +- src/ui_session_interface.rs | 11 +- 66 files changed, 481 insertions(+), 282 deletions(-) diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index 75cedac64..9d255414f 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -548,13 +548,14 @@ jobs: - { target: x86_64-apple-darwin, os: macos-13, #macos-latest or macos-14 use M1 now, https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#:~:text=14%20GB-,macos%2Dlatest%20or%20macos%2D14,-The%20macos%2Dlatestlabel - extra-build-args: "--disable-flutter-texture-render", + extra-build-args: "", arch: x86_64, } - { target: aarch64-apple-darwin, os: macos-latest, - extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296 + # extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296 + extra-build-args: "", arch: aarch64, } steps: @@ -1124,7 +1125,7 @@ jobs: export JOBS="" fi echo $JOBS - cargo build --lib $JOBS --features hwcodec,flutter,flutter_texture_render --release + cargo build --lib $JOBS --features hwcodec,flutter --release rm -rf target/release/deps target/release/build rm -rf ~/.cargo diff --git a/Cargo.toml b/Cargo.toml index 5c35652b9..dfd2020b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ path = "src/naming.rs" [features] inline = [] cli = [] -flutter_texture_render = [] use_samplerate = ["samplerate"] use_rubato = ["rubato"] use_dasp = ["dasp"] diff --git a/build.py b/build.py index c3885c3b7..18dc14ae1 100755 --- a/build.py +++ b/build.py @@ -111,8 +111,6 @@ def make_parser(): 'Available: PrivacyMode. Special value is "ALL" and empty "". Default is empty.') parser.add_argument('--flutter', action='store_true', help='Build flutter package', default=False) - parser.add_argument('--disable-flutter-texture-render', action='store_true', - help='Build flutter package', default=False) parser.add_argument( '--hwcodec', action='store_true', @@ -278,8 +276,6 @@ def get_features(args): features.append('vram') if args.flutter: features.append('flutter') - if not args.disable_flutter_texture_render: - features.append('flutter_texture_render') if args.unix_file_copy_paste: features.append('unix-file-copy-paste') print("features:", features) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index a13fabace..60d2bb73b 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -12,7 +12,6 @@ import 'package:flutter_hbb/common/formatter/id_formatter.dart'; import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/main.dart'; -import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; @@ -2799,11 +2798,6 @@ sessionRefreshVideo(SessionID sessionId, PeerInfo pi) async { } } -bool isChooseDisplayToOpenInNewWindow(PeerInfo pi, SessionID sessionId) => - pi.isSupportMultiDisplay && - useTextureRender && - bind.sessionGetDisplaysAsIndividualWindows(sessionId: sessionId) == 'Y'; - Future> getScreenListWayland() async { final screenRectList = []; if (isMainDesktopWindow) { diff --git a/flutter/lib/common/widgets/setting_widgets.dart b/flutter/lib/common/widgets/setting_widgets.dart index b0bfd5f1f..c91a25164 100644 --- a/flutter/lib/common/widgets/setting_widgets.dart +++ b/flutter/lib/common/widgets/setting_widgets.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/consts.dart'; -import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:get/get.dart'; @@ -227,8 +226,7 @@ List<(String, String)> otherDefaultSettings() { if ((isDesktop || isWebDesktop)) ('Zoom cursor', kOptionZoomCursor), ('Show quality monitor', kOptionShowQualityMonitor), ('Mute', kOptionDisableAudio), - if (isDesktop) - ('Enable file copy and paste', kOptionEnableFileCopyPaste), + if (isDesktop) ('Enable file copy and paste', kOptionEnableFileCopyPaste), ('Disable clipboard', kOptionDisableClipboard), ('Lock after session end', kOptionLockAfterSessionEnd), ('Privacy mode', kOptionPrivacyMode), @@ -236,12 +234,12 @@ List<(String, String)> otherDefaultSettings() { ('True color (4:4:4)', kOptionI444), ('Reverse mouse wheel', kKeyReverseMouseWheel), ('swap-left-right-mouse', kOptionSwapLeftRightMouse), - if (isDesktop && useTextureRender) + if (isDesktop && bind.mainGetUseTextureRender()) ( 'Show displays as individual windows', kKeyShowDisplaysAsIndividualWindows ), - if (isDesktop && useTextureRender) + if (isDesktop && bind.mainGetUseTextureRender()) ( 'Use all my displays for the remote session', kKeyUseAllMyDisplaysForTheRemoteSession diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index b68c0180f..84a03764d 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -8,7 +8,6 @@ import 'package:flutter_hbb/common/widgets/dialog.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; -import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:get/get.dart'; bool isEditOsPassword = false; @@ -581,7 +580,7 @@ Future> toolbarDisplayToggle( child: Text(translate('Lock after session end')))); } - if (useTextureRender && + if (bind.mainGetUseTextureRender() && pi.isSupportMultiDisplay && PrivacyModeState.find(id).isEmpty && pi.displaysCount.value > 1 && @@ -600,7 +599,9 @@ Future> toolbarDisplayToggle( } final isMultiScreens = !isWeb && (await getScreenRectList()).length > 1; - if (useTextureRender && pi.isSupportMultiDisplay && isMultiScreens) { + if (bind.mainGetUseTextureRender() && + pi.isSupportMultiDisplay && + isMultiScreens) { final value = bind.sessionGetUseAllMyDisplaysForTheRemoteSession( sessionId: ffi.sessionId) == 'Y'; diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index be8ee3c17..8ea8549af 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -73,6 +73,7 @@ const String kOptionViewStyle = "view_style"; const String kOptionScrollStyle = "scroll_style"; const String kOptionImageQuality = "image_quality"; const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs"; +const String kOptionTextureRender = "use-texture-render"; const String kOptionOpenInTabs = "allow-open-in-tabs"; const String kOptionOpenInWindows = "allow-open-in-windows"; const String kOptionForceAlwaysRelay = "force-always-relay"; @@ -153,6 +154,8 @@ const String kKeyUseAllMyDisplaysForTheRemoteSession = const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar'; const String kKeyReverseMouseWheel = "reverse_mouse_wheel"; +const String kMsgboxTextWaitingForImage = 'Connected, waiting for image...'; + // the executable name of the portable version const String kEnvPortableExecutable = "RUSTDESK_APPNAME"; diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 1adbe7010..6cb2b2329 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -387,10 +387,25 @@ class _GeneralState extends State<_General> { isServer: false, ), // though this is related to GUI, but opengl problem affects all users, so put in config rather than local + if (isLinux) + Tooltip( + message: translate('software_render_tip'), + child: _OptionCheckBox( + context, + "Always use software rendering", + kOptionAllowAlwaysSoftwareRender, + ), + ), Tooltip( - message: translate('software_render_tip'), - child: _OptionCheckBox(context, "Always use software rendering", - kOptionAllowAlwaysSoftwareRender), + message: translate('texture_render_tip'), + child: _OptionCheckBox( + context, + "Use texture rendering", + kOptionTextureRender, + optGetter: bind.mainGetUseTextureRender, + optSetter: (k, v) async => + await bind.mainSetLocalOption(key: k, value: v ? 'Y' : 'N'), + ), ), if (!bind.isCustomClient()) _OptionCheckBox( @@ -426,7 +441,7 @@ class _GeneralState extends State<_General> { context, 'Remove wallpaper during incoming sessions', kOptionAllowRemoveWallpaper, - update: () { + update: (bool v) { setState(() {}); }, ), @@ -457,8 +472,8 @@ class _GeneralState extends State<_General> { context, 'Enable hardware codec', kOptionEnableHwcodec, - update: () { - if (mainGetBoolOptionSync(kOptionEnableHwcodec)) { + update: (bool v) { + if (v) { bind.mainCheckHwcodec(); } }, @@ -941,7 +956,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { List directIp(BuildContext context) { TextEditingController controller = TextEditingController(); - update() => setState(() {}); + update(bool v) => setState(() {}); RxBool applyEnabled = false.obs; return [ _OptionCheckBox(context, 'Enable direct IP access', kOptionDirectServer, @@ -1102,7 +1117,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { List autoDisconnect(BuildContext context) { TextEditingController controller = TextEditingController(); - update() => setState(() {}); + update(bool v) => setState(() {}); RxBool applyEnabled = false.obs; return [ _OptionCheckBox( @@ -1803,33 +1818,41 @@ Widget _Card( } // ignore: non_constant_identifier_names -Widget _OptionCheckBox(BuildContext context, String label, String key, - {Function()? update, - bool reverse = false, - bool enabled = true, - Icon? checkedIcon, - bool? fakeValue, - bool isServer = true}) { - bool value = - isServer ? mainGetBoolOptionSync(key) : mainGetLocalBoolOptionSync(key); +Widget _OptionCheckBox( + BuildContext context, + String label, + String key, { + Function(bool)? update, + bool reverse = false, + bool enabled = true, + Icon? checkedIcon, + bool? fakeValue, + bool isServer = true, + bool Function()? optGetter, + Future Function(String, bool)? optSetter, +}) { + getOpt() => optGetter != null + ? optGetter() + : (isServer + ? mainGetBoolOptionSync(key) + : mainGetLocalBoolOptionSync(key)); + bool value = getOpt(); final isOptFixed = isOptionFixed(key); if (reverse) value = !value; var ref = value.obs; onChanged(option) async { if (option != null) { if (reverse) option = !option; - isServer - ? await mainSetBoolOption(key, option) - : await mainSetLocalBoolOption(key, option); - final readOption = isServer - ? mainGetBoolOptionSync(key) - : mainGetLocalBoolOptionSync(key); + final setter = + optSetter ?? (isServer ? mainSetBoolOption : mainSetLocalBoolOption); + await setter(key, option); + final readOption = getOpt(); if (reverse) { ref.value = !readOption; } else { ref.value = readOption; } - update?.call(); + update?.call(readOption); } } diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 6fe256cf6..7d4773a32 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -16,7 +16,6 @@ import '../../common.dart'; import '../../common/widgets/dialog.dart'; import '../../common/widgets/toolbar.dart'; import '../../models/model.dart'; -import '../../models/desktop_render_texture.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; import '../../utils/image.dart'; @@ -593,12 +592,11 @@ class _ImagePaintState extends State { onHover: (evt) {}, child: child); }); - if (c.imageOverflow.isTrue && c.scrollStyle == ScrollStyle.scrollbar) { final paintWidth = c.getDisplayWidth() * s; final paintHeight = c.getDisplayHeight() * s; final paintSize = Size(paintWidth, paintHeight); - final paintWidget = useTextureRender + final paintWidget = m.useTextureRender ? _BuildPaintTextureRender( c, s, Offset.zero, paintSize, isViewOriginal()) : _buildScrollbarNonTextureRender(m, paintSize, s); @@ -619,7 +617,7 @@ class _ImagePaintState extends State { )); } else { if (c.size.width > 0 && c.size.height > 0) { - final paintWidget = useTextureRender + final paintWidget = m.useTextureRender ? _BuildPaintTextureRender( c, s, diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 3d2486420..aa6b7de48 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -7,7 +7,6 @@ import 'package:flutter_hbb/common/widgets/audio_input.dart'; import 'package:flutter_hbb/common/widgets/toolbar.dart'; import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/plugin/widgets/desc_ui.dart'; @@ -615,14 +614,14 @@ class _MonitorMenu extends StatelessWidget { bind.mainGetUserDefaultOption(key: kKeyShowMonitorsToolbar) == 'Y'; bool get supportIndividualWindows => - useTextureRender && ffi.ffiModel.pi.isSupportMultiDisplay; + !isWeb && ffi.ffiModel.pi.isSupportMultiDisplay; @override Widget build(BuildContext context) => showMonitorsToolbar - ? buildMultiMonitorMenu() - : Obx(() => buildMonitorMenu()); + ? buildMultiMonitorMenu(context) + : Obx(() => buildMonitorMenu(context)); - Widget buildMonitorMenu() { + Widget buildMonitorMenu(BuildContext context) { final width = SimpleWrapper(0); final monitorsIcon = globalMonitorsWidget(width, Colors.white, Colors.black38); @@ -636,20 +635,23 @@ class _MonitorMenu extends StatelessWidget { menuStyle: MenuStyle( padding: MaterialStatePropertyAll(EdgeInsets.symmetric(horizontal: 6))), - menuChildrenGetter: () => [buildMonitorSubmenuWidget()]); + menuChildrenGetter: () => [buildMonitorSubmenuWidget(context)]); } - Widget buildMultiMonitorMenu() { - return Row(children: buildMonitorList(true)); + Widget buildMultiMonitorMenu(BuildContext context) { + return Row(children: buildMonitorList(context, true)); } - Widget buildMonitorSubmenuWidget() { + Widget buildMonitorSubmenuWidget(BuildContext context) { + final m = Provider.of(context); return Column( mainAxisSize: MainAxisSize.min, children: [ - Row(children: buildMonitorList(false)), - supportIndividualWindows ? Divider() : Offstage(), - supportIndividualWindows ? chooseDisplayBehavior() : Offstage(), + Row(children: buildMonitorList(context, false)), + supportIndividualWindows && m.useTextureRender ? Divider() : Offstage(), + supportIndividualWindows && m.useTextureRender + ? chooseDisplayBehavior() + : Offstage(), ], ); } @@ -680,7 +682,7 @@ class _MonitorMenu extends StatelessWidget { ), ); - List buildMonitorList(bool isMulti) { + List buildMonitorList(BuildContext context, bool isMulti) { final List monitorList = []; final pi = ffi.ffiModel.pi; @@ -735,7 +737,10 @@ class _MonitorMenu extends StatelessWidget { for (int i = 0; i < pi.displays.length; i++) { monitorList.add(buildMonitorButton(i)); } - if (supportIndividualWindows && pi.displays.length > 1) { + final m = Provider.of(context); + if (supportIndividualWindows && + m.useTextureRender && + pi.displays.length > 1) { monitorList.add(buildMonitorButton(kAllDisplayValue)); } return monitorList; @@ -818,7 +823,12 @@ class _MonitorMenu extends StatelessWidget { } RxInt display = CurrentDisplayState.find(id); if (display.value != i) { - if (isChooseDisplayToOpenInNewWindow(pi, ffi.sessionId)) { + final isChooseDisplayToOpenInNewWindow = pi.isSupportMultiDisplay && + bind.mainGetUseTextureRender() && + bind.sessionGetDisplaysAsIndividualWindows( + sessionId: ffi.sessionId) == + 'Y'; + if (isChooseDisplayToOpenInNewWindow) { openMonitorInNewTabOrWindow(i, ffi.id, pi); } else { openMonitorInTheSameTab(i, ffi, pi, updateCursorPos: !isMulti); diff --git a/flutter/lib/models/desktop_render_texture.dart b/flutter/lib/models/desktop_render_texture.dart index 3078115bb..ab8df3c45 100644 --- a/flutter/lib/models/desktop_render_texture.dart +++ b/flutter/lib/models/desktop_render_texture.dart @@ -11,15 +11,10 @@ import './platform_model.dart'; import 'package:texture_rgba_renderer/texture_rgba_renderer.dart' if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart'; -// Feature flutter_texture_render need to be enabled if feature vram is enabled. -final useTextureRender = !isWeb && - (bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender()); - class _PixelbufferTexture { int _textureKey = -1; int _display = 0; SessionID? _sessionId; - final support = bind.mainHasPixelbufferTextureRender(); bool _destroying = false; int? _id; @@ -28,26 +23,24 @@ class _PixelbufferTexture { int get display => _display; create(int d, SessionID sessionId, FFI ffi) { - if (support) { - _display = d; - _textureKey = bind.getNextTextureKey(); - _sessionId = sessionId; + _display = d; + _textureKey = bind.getNextTextureKey(); + _sessionId = sessionId; - textureRenderer.createTexture(_textureKey).then((id) async { - _id = id; - if (id != -1) { - ffi.textureModel.setRgbaTextureId(display: d, id: id); - final ptr = await textureRenderer.getTexturePtr(_textureKey); - platformFFI.registerPixelbufferTexture(sessionId, display, ptr); - debugPrint( - "create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr"); - } - }); - } + textureRenderer.createTexture(_textureKey).then((id) async { + _id = id; + if (id != -1) { + ffi.textureModel.setRgbaTextureId(display: d, id: id); + final ptr = await textureRenderer.getTexturePtr(_textureKey); + platformFFI.registerPixelbufferTexture(sessionId, display, ptr); + debugPrint( + "create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr"); + } + }); } destroy(bool unregisterTexture, FFI ffi) async { - if (!_destroying && support && _textureKey != -1 && _sessionId != null) { + if (!_destroying && _textureKey != -1 && _sessionId != null) { _destroying = true; if (unregisterTexture) { platformFFI.registerPixelbufferTexture(_sessionId!, display, 0); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a83c381ed..0200a1af3 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -244,7 +244,7 @@ class FfiModel with ChangeNotifier { handleMsgBox({ 'type': 'success', 'title': 'Successful', - 'text': 'Connected, waiting for image...', + 'text': kMsgboxTextWaitingForImage, 'link': '', }, sessionId, peerId); updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId); @@ -380,12 +380,22 @@ class FfiModel with ChangeNotifier { _handleSyncPeerOption(evt, peerId); } else if (name == 'follow_current_display') { handleFollowCurrentDisplay(evt, sessionId, peerId); + } else if (name == 'use_texture_render') { + _handleUseTextureRender(evt, sessionId, peerId); } else { debugPrint('Unknown event name: $name'); } }; } + _handleUseTextureRender( + Map evt, SessionID sessionId, String peerId) { + parent.target?.imageModel.setUseTextureRender(evt['v'] == 'Y'); + waitForFirstImage.value = true; + showConnectedWaitingForImage(parent.target!.dialogManager, sessionId, + 'success', 'Successful', kMsgboxTextWaitingForImage); + } + _handleSyncPeerOption(Map evt, String peer) { final k = evt['k']; final v = evt['v']; @@ -572,7 +582,7 @@ class FfiModel with ChangeNotifier { showElevationError(sessionId, type, title, text, dialogManager); } else if (type == 'relay-hint' || type == 'relay-hint2') { showRelayHintDialog(sessionId, type, title, text, dialogManager, peerId); - } else if (text == 'Connected, waiting for image...') { + } else if (text == kMsgboxTextWaitingForImage) { showConnectedWaitingForImage(dialogManager, sessionId, type, title, text); } else if (title == 'Privacy mode') { final hasRetry = evt['hasRetry'] == 'true'; @@ -1156,6 +1166,8 @@ class ImageModel with ChangeNotifier { late final SessionID sessionId; + bool _useTextureRender = false; + WeakReference parent; final List callbacksOnFirstImage = []; @@ -1164,6 +1176,8 @@ class ImageModel with ChangeNotifier { sessionId = parent.target!.sessionId; } + get useTextureRender => _useTextureRender; + addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb); onRgba(int display, Uint8List rgba) { @@ -1233,6 +1247,19 @@ class ImageModel with ChangeNotifier { return min(xscale, yscale) / 1.5; } + updateUserTextureRender() { + final preValue = _useTextureRender; + _useTextureRender = isDesktop && bind.mainGetUseTextureRender(); + if (preValue != _useTextureRender) { + notifyListeners(); + } + } + + setUseTextureRender(bool value) { + _useTextureRender = value; + notifyListeners(); + } + void disposeImage() { _image?.dispose(); _image = null; @@ -2387,7 +2414,7 @@ class FFI { sessionId: sessionId, displays: Int32List.fromList(displays)); ffiModel.pi.currentDisplay = display; } - if (connType == ConnType.defaultConn && useTextureRender) { + if (isDesktop && connType == ConnType.defaultConn) { textureModel.updateCurrentDisplay(display ?? 0); } final stream = bind.sessionStart(sessionId: sessionId, id: id); @@ -2409,9 +2436,8 @@ class FFI { } } - final hasPixelBufferTextureRender = bind.mainHasPixelbufferTextureRender(); + imageModel.updateUserTextureRender(); final hasGpuTextureRender = bind.mainHasGpuTextureRender(); - final SimpleWrapper isToNewWindowNotified = SimpleWrapper(false); // Preserved for the rgba data. stream.listen((message) { @@ -2460,7 +2486,7 @@ class FFI { } } else if (message is EventToUI_Rgba) { final display = message.field0; - if (hasPixelBufferTextureRender) { + if (imageModel.useTextureRender) { debugPrint("EventToUI_Rgba display:$display"); textureModel.setTextureType(display: display, gpuTexture: false); onEvent2UIRgba(); diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index 3439fb97e..3589b3f31 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -1414,10 +1414,6 @@ class RustdeskImpl { throw UnimplementedError(); } - bool mainHasPixelbufferTextureRender({dynamic hint}) { - return false; - } - bool mainHasFileClipboard({dynamic hint}) { return false; } @@ -1608,5 +1604,9 @@ class RustdeskImpl { throw UnimplementedError(); } + bool mainGetUseTextureRender({dynamic hint}) { + throw UnimplementedError(); + } + void dispose() {} } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index dc15d4766..a36e26b5b 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -2053,6 +2053,7 @@ pub mod keys { pub const OPTION_ENABLE_CONFIRM_CLOSING_TABS: &str = "enable-confirm-closing-tabs"; pub const OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS: &str = "enable-open-new-connections-in-tabs"; + pub const OPTION_TEXTURE_RENDER: &str = "use-texture-render"; pub const OPTION_ENABLE_CHECK_UPDATE: &str = "enable-check-update"; pub const OPTION_SYNC_AB_WITH_RECENT_SESSIONS: &str = "sync-ab-with-recent-sessions"; pub const OPTION_SYNC_AB_TAGS: &str = "sync-ab-tags"; @@ -2133,6 +2134,7 @@ pub mod keys { OPTION_LANGUAGE, OPTION_ENABLE_CONFIRM_CLOSING_TABS, OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS, + OPTION_TEXTURE_RENDER, OPTION_SYNC_AB_WITH_RECENT_SESSIONS, OPTION_SYNC_AB_TAGS, OPTION_FILTER_AB_BY_INTERSECTION, diff --git a/libs/scrap/src/common/codec.rs b/libs/scrap/src/common/codec.rs index 7aba012ba..098daa998 100644 --- a/libs/scrap/src/common/codec.rs +++ b/libs/scrap/src/common/codec.rs @@ -419,7 +419,7 @@ impl Encoder { impl Decoder { pub fn supported_decodings( id_for_perfer: Option<&str>, - _flutter: bool, + _use_texture_render: bool, _luid: Option, mark_unsupported: &Vec, ) -> SupportedDecoding { @@ -454,7 +454,7 @@ impl Decoder { }; } #[cfg(feature = "vram")] - if enable_vram_option() && _flutter { + if enable_vram_option() && _use_texture_render { decoding.ability_h264 |= if VRamDecoder::available(CodecFormat::H264, _luid).len() > 0 { 1 } else { diff --git a/libs/scrap/src/common/mod.rs b/libs/scrap/src/common/mod.rs index 8804ae5f1..91ca6b7af 100644 --- a/libs/scrap/src/common/mod.rs +++ b/libs/scrap/src/common/mod.rs @@ -88,6 +88,11 @@ impl ImageRgb { pub fn stride(&self) -> usize { self.stride } + + #[inline] + pub fn set_stride(&mut self, stride: usize) { + self.stride = stride; + } } #[inline] diff --git a/src/client.rs b/src/client.rs index 111576595..684b9cff0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -39,7 +39,7 @@ use hbb_common::{ }, get_version_number, log, message_proto::{option_message::BoolOption, *}, - protobuf::Message as _, + protobuf::{Message as _, MessageField}, rand, rendezvous_proto::*, socket_client, @@ -61,6 +61,7 @@ use crate::{ check_port, common::input::{MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP}, create_symmetric_key_msg, decode_id_pk, get_rs_pk, is_keyboard_mode_supported, secure_tcp, + ui_interface::use_texture_render, ui_session_interface::{InvokeUiSession, Session}, }; @@ -1035,16 +1036,23 @@ pub struct VideoHandler { } impl VideoHandler { + #[cfg(feature = "flutter")] + pub fn get_adapter_luid() -> Option { + crate::flutter::get_adapter_luid() + } + + #[cfg(not(feature = "flutter"))] + pub fn get_adapter_luid() -> Option { + None + } + /// Create a new video handler. pub fn new(format: CodecFormat, _display: usize) -> Self { - #[cfg(all(feature = "vram", feature = "flutter"))] - let luid = crate::flutter::get_adapter_luid(); - #[cfg(not(all(feature = "vram", feature = "flutter")))] - let luid = Default::default(); + let luid = Self::get_adapter_luid(); log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}"); VideoHandler { decoder: Decoder::new(format, luid), - rgb: ImageRgb::new(ImageFormat::ARGB, crate::DST_STRIDE_RGBA), + rgb: ImageRgb::new(ImageFormat::ARGB, crate::get_dst_stride_rgba()), texture: std::ptr::null_mut(), recorder: Default::default(), record: false, @@ -1096,10 +1104,9 @@ impl VideoHandler { /// Reset the decoder, change format if it is Some pub fn reset(&mut self, format: Option) { - #[cfg(all(feature = "flutter", feature = "vram"))] - let luid = crate::flutter::get_adapter_luid(); - #[cfg(not(all(feature = "flutter", feature = "vram")))] - let luid = None; + #[cfg(target_os = "macos")] + self.rgb.set_stride(crate::get_dst_stride_rgba()); + let luid = Self::get_adapter_luid(); let format = format.unwrap_or(self.decoder.format()); self.decoder = Decoder::new(format, luid); self.fail_counter = 0; @@ -1637,16 +1644,19 @@ impl LoginConfigHandler { if view_only || self.get_toggle_option("disable-clipboard") { msg.disable_clipboard = BoolOption::Yes.into(); } - msg.supported_decoding = - hbb_common::protobuf::MessageField::some(Decoder::supported_decodings( - Some(&self.id), - cfg!(feature = "flutter"), - self.adapter_luid, - &self.mark_unsupported, - )); + msg.supported_decoding = MessageField::some(self.get_supported_decoding()); Some(msg) } + pub fn get_supported_decoding(&self) -> SupportedDecoding { + Decoder::supported_decodings( + Some(&self.id), + use_texture_render(), + self.adapter_luid, + &self.mark_unsupported, + ) + } + pub fn get_option_message_after_login(&self) -> Option { if self.conn_type.eq(&ConnType::FILE_TRANSFER) || self.conn_type.eq(&ConnType::PORT_FORWARD) @@ -2036,7 +2046,7 @@ impl LoginConfigHandler { pub fn update_supported_decodings(&self) -> Message { let decoding = scrap::codec::Decoder::supported_decodings( Some(&self.id), - cfg!(feature = "flutter"), + use_texture_render(), self.adapter_luid, &self.mark_unsupported, ); @@ -2065,7 +2075,7 @@ pub enum MediaData { VideoFrame(Box), AudioFrame(Box), AudioFormat(AudioFormat), - Reset(usize), + Reset(Option), RecordScreen(bool, usize, i32, i32, String), } @@ -2241,8 +2251,16 @@ where } } MediaData::Reset(display) => { - if let Some(handler_controler) = handler_controller_map.get_mut(&display) { - handler_controler.handler.reset(None); + if let Some(display) = display { + if let Some(handler_controler) = + handler_controller_map.get_mut(&display) + { + handler_controler.handler.reset(None); + } + } else { + for (_, handler_controler) in handler_controller_map.iter_mut() { + handler_controler.handler.reset(None); + } } } MediaData::RecordScreen(start, display, w, h, id) => { @@ -2945,6 +2963,7 @@ pub enum Data { ElevateWithLogon(String, String), NewVoiceCall, CloseVoiceCall, + ResetDecoder(Option), } /// Keycode for key events. diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 54f98738f..758ba8a13 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -843,6 +843,9 @@ impl Remote { .on_voice_call_closed("Closed manually by the peer"); allow_err!(peer.send(&msg).await); } + Data::ResetDecoder(display) => { + self.video_sender.send(MediaData::Reset(display)).ok(); + } _ => {} } true @@ -1371,7 +1374,7 @@ impl Remote { Some(misc::Union::SwitchDisplay(s)) => { self.handler.handle_peer_switch_display(&s); self.video_sender - .send(MediaData::Reset(s.display as _)) + .send(MediaData::Reset(Some(s.display as _))) .ok(); if s.width > 0 && s.height > 0 { self.handler.set_display( diff --git a/src/common.rs b/src/common.rs index 842ada647..5d5a1b7e7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -158,13 +158,6 @@ pub type NotifyMessageBox = fn(String, String, String, String) -> dyn Future usize { + // https://developer.apple.com/forums/thread/712709 + // Memory alignment should be multiple of 64. + if crate::ui_interface::use_texture_render() { + 64 + } else { + 1 + } +} + +#[inline] +#[cfg(not(target_os = "macos"))] +pub fn get_dst_stride_rgba() -> usize { + 1 +} + pub fn read_custom_client(config: &str) { let Ok(data) = decode64(config) else { log::error!("Failed to decode custom client config"); diff --git a/src/flutter.rs b/src/flutter.rs index 29b026561..25b7d3aeb 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -4,7 +4,7 @@ use crate::{ ui_session_interface::{io_loop, InvokeUiSession, Session}, }; use flutter_rust_bridge::StreamSink; -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] +#[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::dlopen::{ symbor::{Library, Symbol}, Error as LibError, @@ -16,15 +16,15 @@ use hbb_common::{ use serde::Serialize; use serde_json::json; -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] -use std::os::raw::c_void; - use std::{ collections::HashMap, ffi::CString, - os::raw::{c_char, c_int}, + os::raw::{c_char, c_int, c_void}, str::FromStr, - sync::{Arc, RwLock}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, RwLock, + }, }; /// tag "main" for [Desktop Main Page] and [Mobile (Client and Server)] (the mobile don't need multiple windows, only one global event stream is needed) @@ -48,22 +48,22 @@ lazy_static::lazy_static! { static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } -#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))] +#[cfg(target_os = "windows")] lazy_static::lazy_static! { pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result = Library::open("texture_rgba_renderer_plugin.dll"); } -#[cfg(all(target_os = "linux", feature = "flutter_texture_render"))] +#[cfg(target_os = "linux")] lazy_static::lazy_static! { pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result = Library::open("libtexture_rgba_renderer_plugin.so"); } -#[cfg(all(target_os = "macos", feature = "flutter_texture_render"))] +#[cfg(target_os = "macos")] lazy_static::lazy_static! { pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result = Library::open_self(); } -#[cfg(all(target_os = "windows", feature = "vram"))] +#[cfg(target_os = "windows")] lazy_static::lazy_static! { pub static ref TEXTURE_GPU_RENDERER_PLUGIN: Result = Library::open("flutter_gpu_texture_renderer_plugin.dll"); } @@ -168,11 +168,9 @@ pub unsafe extern "C" fn get_rustdesk_app_name(buffer: *mut u16, length: i32) -> #[derive(Default)] struct SessionHandler { event_stream: Option>, - #[cfg(any(feature = "flutter_texture_render", feature = "vram"))] renderer: VideoRenderer, } -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] enum RenderType { PixelBuffer, @@ -180,22 +178,32 @@ enum RenderType { Texture, } -#[derive(Default, Clone)] +#[derive(Clone)] pub struct FlutterHandler { // ui session id -> display handler data session_handlers: Arc>>, - #[cfg(not(feature = "flutter_texture_render"))] display_rgbas: Arc>>, peer_info: Arc>, - #[cfg(any( - not(feature = "flutter_texture_render"), - all(feature = "flutter_texture_render", feature = "plugin_framework") - ))] #[cfg(not(any(target_os = "android", target_os = "ios")))] hooks: Arc>>, + use_texture_render: Arc, +} + +impl Default for FlutterHandler { + fn default() -> Self { + Self { + session_handlers: Default::default(), + display_rgbas: Default::default(), + peer_info: Default::default(), + #[cfg(not(any(target_os = "android", target_os = "ios")))] + hooks: Default::default(), + use_texture_render: Arc::new( + AtomicBool::new(crate::ui_interface::use_texture_render()), + ), + } + } } -#[cfg(not(feature = "flutter_texture_render"))] #[derive(Default, Clone)] struct RgbaData { // SAFETY: [rgba] is guarded by [rgba_valid], and it's safe to reach [rgba] with `rgba_valid == true`. @@ -204,7 +212,6 @@ struct RgbaData { valid: bool, } -#[cfg(feature = "flutter_texture_render")] pub type FlutterRgbaRendererPluginOnRgba = unsafe extern "C" fn( texture_rgba: *mut c_void, buffer: *const u8, @@ -221,15 +228,11 @@ pub type FlutterGpuTextureRendererPluginCApiSetTexture = #[cfg(feature = "vram")] pub type FlutterGpuTextureRendererPluginCApiGetAdapterLuid = unsafe extern "C" fn() -> i64; -#[cfg(feature = "flutter_texture_render")] pub(super) type TextureRgbaPtr = usize; -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] struct DisplaySessionInfo { // TextureRgba pointer in flutter native. - #[cfg(feature = "flutter_texture_render")] texture_rgba_ptr: TextureRgbaPtr, - #[cfg(feature = "flutter_texture_render")] size: (usize, usize), #[cfg(feature = "vram")] gpu_output_ptr: usize, @@ -237,21 +240,19 @@ struct DisplaySessionInfo { } // Video Texture Renderer in Flutter -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] #[derive(Clone)] struct VideoRenderer { is_support_multi_ui_session: bool, map_display_sessions: Arc>>, - #[cfg(feature = "flutter_texture_render")] + #[cfg(not(any(target_os = "android", target_os = "ios")))] on_rgba_func: Option>, #[cfg(feature = "vram")] on_texture_func: Option>, } -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] impl Default for VideoRenderer { fn default() -> Self { - #[cfg(feature = "flutter_texture_render")] + #[cfg(not(any(target_os = "android", target_os = "ios")))] let on_rgba_func = match &*TEXTURE_RGBA_RENDERER_PLUGIN { Ok(lib) => { let find_sym_res = unsafe { @@ -295,7 +296,7 @@ impl Default for VideoRenderer { Self { map_display_sessions: Default::default(), is_support_multi_ui_session: false, - #[cfg(feature = "flutter_texture_render")] + #[cfg(not(any(target_os = "android", target_os = "ios")))] on_rgba_func, #[cfg(feature = "vram")] on_texture_func, @@ -303,10 +304,8 @@ impl Default for VideoRenderer { } } -#[cfg(any(feature = "flutter_texture_render", feature = "vram"))] impl VideoRenderer { #[inline] - #[cfg(feature = "flutter_texture_render")] fn set_size(&mut self, display: usize, width: usize, height: usize) { let mut sessions_lock = self.map_display_sessions.write().unwrap(); if let Some(info) = sessions_lock.get_mut(&display) { @@ -326,7 +325,6 @@ impl VideoRenderer { } } - #[cfg(feature = "flutter_texture_render")] fn register_pixelbuffer_texture(&self, display: usize, ptr: usize) { let mut sessions_lock = self.map_display_sessions.write().unwrap(); if ptr == 0 { @@ -378,7 +376,6 @@ impl VideoRenderer { if info.gpu_output_ptr != usize::default() { info.gpu_output_ptr = usize::default(); } - #[cfg(feature = "flutter_texture_render")] if info.texture_rgba_ptr != usize::default() { return; } @@ -400,9 +397,7 @@ impl VideoRenderer { sessions_lock.insert( display, DisplaySessionInfo { - #[cfg(feature = "flutter_texture_render")] texture_rgba_ptr: usize::default(), - #[cfg(feature = "flutter_texture_render")] size: (0, 0), gpu_output_ptr: ptr, notify_render_type: None, @@ -413,7 +408,7 @@ impl VideoRenderer { } } - #[cfg(feature = "flutter_texture_render")] + #[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(); let opt_info = if !self.is_support_multi_ui_session { @@ -498,10 +493,7 @@ impl VideoRenderer { impl SessionHandler { pub fn on_waiting_for_image_dialog_show(&self) { - #[cfg(any(feature = "flutter_texture_render"))] - { - self.renderer.reset_all_display_render_type(); - } + self.renderer.reset_all_display_render_type(); // rgba array render will notify every frame } } @@ -583,6 +575,11 @@ impl FlutterHandler { let _ = hooks.remove(key); true } + + pub fn update_use_texture_render(&self) { + self.use_texture_render + .store(crate::ui_interface::use_texture_render(), Ordering::Relaxed); + } } impl InvokeUiSession for FlutterHandler { @@ -769,60 +766,27 @@ impl InvokeUiSession for FlutterHandler { fn adapt_size(&self) {} #[inline] - #[cfg(not(feature = "flutter_texture_render"))] + #[cfg(not(any(target_os = "android", target_os = "ios")))] fn on_rgba(&self, display: usize, rgba: &mut scrap::ImageRgb) { - // Give a chance for plugins or etc to hook a rgba data. - #[cfg(not(any(target_os = "android", target_os = "ios")))] - for (key, hook) in self.hooks.read().unwrap().iter() { - match hook { - SessionHook::OnSessionRgba(cb) => { - cb(key.to_owned(), rgba); - } - } - } - // If the current rgba is not fetched by flutter, i.e., is valid. - // We give up sending a new event to flutter. - let mut rgba_write_lock = self.display_rgbas.write().unwrap(); - if let Some(rgba_data) = rgba_write_lock.get_mut(&display) { - if rgba_data.valid { - return; - } else { - rgba_data.valid = true; - } - // Return the rgba buffer to the video handler for reusing allocated rgba buffer. - std::mem::swap::>(&mut rgba.raw, &mut rgba_data.data); + if self.use_texture_render.load(Ordering::Relaxed) { + self.on_rgba_flutter_texture_render(display, rgba); } else { - let mut rgba_data = RgbaData::default(); - std::mem::swap::>(&mut rgba.raw, &mut rgba_data.data); - rgba_data.valid = true; - rgba_write_lock.insert(display, rgba_data); - } - drop(rgba_write_lock); - - // Non-texture-render UI does not support multiple displays in the one UI session. - // It's Ok to notify each session for now. - for h in self.session_handlers.read().unwrap().values() { - if let Some(stream) = &h.event_stream { - stream.add(EventToUI::Rgba(display)); - } + self.on_rgba_soft_render(display, rgba); } } #[inline] - #[cfg(feature = "flutter_texture_render")] + #[cfg(any(target_os = "android", target_os = "ios"))] fn on_rgba(&self, display: usize, rgba: &mut scrap::ImageRgb) { - for (_, session) in self.session_handlers.read().unwrap().iter() { - if session.renderer.on_rgba(display, rgba) { - if let Some(stream) = &session.event_stream { - stream.add(EventToUI::Rgba(display)); - } - } - } + self.on_rgba_soft_render(display, rgba); } #[inline] #[cfg(feature = "vram")] fn on_texture(&self, display: usize, texture: *mut c_void) { + if !self.use_texture_render.load(Ordering::Relaxed) { + return; + } for (_, session) in self.session_handlers.read().unwrap().iter() { if session.renderer.on_texture(display, texture) { if let Some(stream) = &session.event_stream { @@ -845,17 +809,17 @@ impl InvokeUiSession for FlutterHandler { let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned()); let resolutions = serialize_resolutions(&pi.resolutions.resolutions); *self.peer_info.write().unwrap() = pi.clone(); - #[cfg(feature = "flutter_texture_render")] - { - self.session_handlers - .write() - .unwrap() - .values_mut() - .for_each(|h| { - h.renderer.is_support_multi_ui_session = - crate::common::is_support_multi_ui_session(&pi.version); - }); - } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + let is_support_multi_ui_session = crate::common::is_support_multi_ui_session(&pi.version); + #[cfg(any(target_os = "android", target_os = "ios"))] + let is_support_multi_ui_session = false; + self.session_handlers + .write() + .unwrap() + .values_mut() + .for_each(|h| { + h.renderer.is_support_multi_ui_session = is_support_multi_ui_session; + }); self.push_event( "peer_info", &[ @@ -1028,7 +992,6 @@ impl InvokeUiSession for FlutterHandler { #[inline] fn get_rgba(&self, _display: usize) -> *const u8 { - #[cfg(not(feature = "flutter_texture_render"))] if let Some(rgba_data) = self.display_rgbas.read().unwrap().get(&_display) { if rgba_data.valid { return rgba_data.data.as_ptr(); @@ -1039,13 +1002,65 @@ impl InvokeUiSession for FlutterHandler { #[inline] fn next_rgba(&self, _display: usize) { - #[cfg(not(feature = "flutter_texture_render"))] if let Some(rgba_data) = self.display_rgbas.write().unwrap().get_mut(&_display) { rgba_data.valid = false; } } } +impl FlutterHandler { + #[inline] + fn on_rgba_soft_render(&self, display: usize, rgba: &mut scrap::ImageRgb) { + // Give a chance for plugins or etc to hook a rgba data. + #[cfg(not(any(target_os = "android", target_os = "ios")))] + for (key, hook) in self.hooks.read().unwrap().iter() { + match hook { + SessionHook::OnSessionRgba(cb) => { + cb(key.to_owned(), rgba); + } + } + } + // If the current rgba is not fetched by flutter, i.e., is valid. + // We give up sending a new event to flutter. + let mut rgba_write_lock = self.display_rgbas.write().unwrap(); + if let Some(rgba_data) = rgba_write_lock.get_mut(&display) { + if rgba_data.valid { + return; + } else { + rgba_data.valid = true; + } + // Return the rgba buffer to the video handler for reusing allocated rgba buffer. + std::mem::swap::>(&mut rgba.raw, &mut rgba_data.data); + } else { + let mut rgba_data = RgbaData::default(); + std::mem::swap::>(&mut rgba.raw, &mut rgba_data.data); + rgba_data.valid = true; + rgba_write_lock.insert(display, rgba_data); + } + drop(rgba_write_lock); + + // Non-texture-render UI does not support multiple displays in the one UI session. + // It's Ok to notify each session for now. + for h in self.session_handlers.read().unwrap().values() { + if let Some(stream) = &h.event_stream { + stream.add(EventToUI::Rgba(display)); + } + } + } + + #[inline] + #[cfg(not(any(target_os = "android", target_os = "ios")))] + fn on_rgba_flutter_texture_render(&self, display: usize, rgba: &mut scrap::ImageRgb) { + for (_, session) in self.session_handlers.read().unwrap().iter() { + if session.renderer.on_rgba(display, rgba) { + if let Some(stream) = &session.event_stream { + stream.add(EventToUI::Rgba(display)); + } + } + } + } +} + // 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); @@ -1116,17 +1131,12 @@ pub fn session_add( Some(switch_uuid.to_string()) }; - #[cfg(feature = "vram")] - let adapter_luid = get_adapter_luid(); - #[cfg(not(feature = "vram"))] - let adapter_luid = None; - session.lc.write().unwrap().initialize( id.to_owned(), conn_type, switch_uuid, force_relay, - adapter_luid, + get_adapter_luid(), shared_password, ); @@ -1172,14 +1182,11 @@ pub fn session_start_( if let Some(session) = sessions::get_session_by_session_id(session_id) { let is_first_ui_session = session.session_handlers.read().unwrap().len() == 1; if !is_connected && is_first_ui_session { - #[cfg(feature = "flutter_texture_render")] log::info!( - "Session {} start, render by flutter texture rgba plugin", - id + "Session {} start, use texture render: {}", + id, + session.use_texture_render.load(Ordering::Relaxed) ); - #[cfg(not(feature = "flutter_texture_render"))] - log::info!("Session {} start, render by flutter paint widget", id); - let session = (*session).clone(); std::thread::spawn(move || { let round = session.connection_round_state.lock().unwrap().new_round(); @@ -1437,14 +1444,13 @@ fn char_to_session_id(c: *const char) -> ResultType { SessionID::from_str(str).map_err(|e| anyhow!("{:?}", e)) } -pub fn session_get_rgba_size(_session_id: SessionID, _display: usize) -> usize { - #[cfg(not(feature = "flutter_texture_render"))] - if let Some(session) = sessions::get_session_by_session_id(&_session_id) { +pub fn session_get_rgba_size(session_id: SessionID, display: usize) -> usize { + if let Some(session) = sessions::get_session_by_session_id(&session_id) { return session .display_rgbas .read() .unwrap() - .get(&_display) + .get(&display) .map_or(0, |rgba| rgba.data.len()); } 0 @@ -1468,34 +1474,32 @@ pub fn session_next_rgba(session_id: SessionID, display: usize) { } #[inline] -pub fn session_set_size(_session_id: SessionID, _display: usize, _width: usize, _height: usize) { - #[cfg(feature = "flutter_texture_render")] +pub fn session_set_size(session_id: SessionID, display: usize, width: usize, height: usize) { for s in sessions::get_sessions() { if let Some(h) = s .ui_handler .session_handlers .write() .unwrap() - .get_mut(&_session_id) + .get_mut(&session_id) { - h.renderer.set_size(_display, _width, _height); + h.renderer.set_size(display, width, height); break; } } } #[inline] -pub fn session_register_pixelbuffer_texture(_session_id: SessionID, _display: usize, _ptr: usize) { - #[cfg(feature = "flutter_texture_render")] +pub fn session_register_pixelbuffer_texture(session_id: SessionID, display: usize, ptr: usize) { for s in sessions::get_sessions() { if let Some(h) = s .ui_handler .session_handlers .read() .unwrap() - .get(&_session_id) + .get(&session_id) { - h.renderer.register_pixelbuffer_texture(_display, _ptr); + h.renderer.register_pixelbuffer_texture(display, ptr); break; } } @@ -1518,8 +1522,17 @@ pub fn session_register_gpu_texture(_session_id: SessionID, _display: usize, _ou } } +#[inline] +#[cfg(not(feature = "vram"))] +pub fn get_adapter_luid() -> Option { + None +} + #[cfg(feature = "vram")] pub fn get_adapter_luid() -> Option { + if !crate::ui_interface::use_texture_render() { + return None; + } let get_adapter_luid_func = match &*TEXTURE_GPU_RENDERER_PLUGIN { Ok(lib) => { let find_sym_res = unsafe { @@ -1713,7 +1726,6 @@ pub fn try_sync_peer_option( // sessions mod is used to avoid the big lock of sessions' map. pub mod sessions { - #[cfg(feature = "flutter_texture_render")] use std::collections::HashSet; use super::*; @@ -1781,14 +1793,6 @@ pub mod sessions { for (peer_key, s) in SESSIONS.write().unwrap().iter_mut() { let mut write_lock = s.ui_handler.session_handlers.write().unwrap(); let remove_ret = write_lock.remove(id); - #[cfg(not(feature = "flutter_texture_render"))] - if remove_ret.is_some() { - if write_lock.is_empty() { - remove_peer_key = Some(peer_key.clone()); - } - break; - } - #[cfg(feature = "flutter_texture_render")] match remove_ret { Some(_) => { if write_lock.is_empty() { @@ -1804,7 +1808,6 @@ pub mod sessions { SESSIONS.write().unwrap().remove(&remove_peer_key?) } - #[cfg(feature = "flutter_texture_render")] fn check_remove_unused_displays( current: Option, session_id: &SessionID, @@ -1852,7 +1855,6 @@ pub mod sessions { s.capture_displays(vec![], vec![], value); } else { // Check if other displays are needed. - #[cfg(feature = "flutter_texture_render")] if value.len() == 1 { check_remove_unused_displays( Some(value[0] as _), @@ -1892,16 +1894,14 @@ pub mod sessions { session_id: SessionID, ) -> bool { if let Some(s) = SESSIONS.read().unwrap().get(&(peer_id, conn_type)) { - #[cfg(not(feature = "flutter_texture_render"))] - let h = SessionHandler::default(); - #[cfg(feature = "flutter_texture_render")] let mut h = SessionHandler::default(); - #[cfg(feature = "flutter_texture_render")] - { - h.renderer.is_support_multi_ui_session = crate::common::is_support_multi_ui_session( - &s.ui_handler.peer_info.read().unwrap().version, - ); - } + #[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, + ); + #[cfg(any(target_os = "android", target_os = "ios"))] + let is_support_multi_ui_session = false; + h.renderer.is_support_multi_ui_session = is_support_multi_ui_session; let _ = s .ui_handler .session_handlers diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 35c436f2b..dae8d3fc1 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -2,7 +2,7 @@ use crate::{ client::file_trait::FileManager, common::{is_keyboard_mode_supported, make_fd_to_json}, flutter::{ - self, session_add, session_add_existed, session_start_, sessions, try_sync_peer_option, + self, session_add, session_add_existed, session_start_, sessions, try_sync_peer_option, FlutterHandler, }, input::*, ui_interface::{self, *}, @@ -711,9 +711,8 @@ pub fn session_change_resolution(session_id: SessionID, display: i32, width: i32 } } -pub fn session_set_size(_session_id: SessionID, _display: usize, _width: usize, _height: usize) { - #[cfg(feature = "flutter_texture_render")] - super::flutter::session_set_size(_session_id, _display, _width, _height) +pub fn session_set_size(session_id: SessionID, display: usize, width: usize, height: usize) { + super::flutter::session_set_size(session_id, display, width, height) } pub fn session_send_selected_session_id(session_id: SessionID, sid: String) { @@ -774,13 +773,13 @@ pub fn main_show_option(_key: String) -> SyncReturn { pub fn main_set_option(key: String, value: String) { if key.eq("custom-rendezvous-server") { - set_option(key, value); + set_option(key, value.clone()); #[cfg(target_os = "android")] crate::rendezvous_mediator::RendezvousMediator::restart(); #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] crate::common::test_rendezvous_server(); } else { - set_option(key, value); + set_option(key, value.clone()); } } @@ -892,12 +891,25 @@ pub fn main_get_local_option(key: String) -> SyncReturn { SyncReturn(get_local_option(key)) } +pub fn main_get_use_texture_render() -> SyncReturn { + SyncReturn(use_texture_render()) +} + pub fn main_get_env(key: String) -> SyncReturn { SyncReturn(std::env::var(key).unwrap_or_default()) } pub fn main_set_local_option(key: String, value: String) { - set_local_option(key, value) + let is_texture_render_key = key.eq(config::keys::OPTION_TEXTURE_RENDER); + set_local_option(key, value.clone()); + if is_texture_render_key { + let session_event = [("v", &value)]; + for session in sessions::get_sessions() { + session.push_event("use_texture_render", &session_event, &[]); + session.use_texture_render_changed(); + session.ui_handler.update_use_texture_render(); + } + } } // We do use use `main_get_local_option` and `main_set_local_option`. @@ -1824,10 +1836,6 @@ pub fn main_hide_docker() -> SyncReturn { SyncReturn(true) } -pub fn main_has_pixelbuffer_texture_render() -> SyncReturn { - SyncReturn(cfg!(feature = "flutter_texture_render")) -} - pub fn main_has_file_clipboard() -> SyncReturn { let ret = cfg!(any( target_os = "windows", diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 617b0c571..79af7728c 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/bg.rs b/src/lang/bg.rs index 80b602a39..5cdfccaa1 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 8b6ea652d..baef93c71 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 61f6c3516..b6af828a4 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "清除 Wayland 的屏幕选择后,您可以重新选择分享的屏幕。"), ("confirm_clear_Wayland_screen_selection_tip", "是否确认清除 Wayland 的分享屏幕选择?"), ("android_new_voice_call_tip", "收到新的语音呼叫请求。如果您接受,音频将切换为语音通信。"), + ("texture_render_tip", "使用纹理渲染,使图片更加流畅。"), + ("Use texture rendering", "使用纹理渲染"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 783dcfeb7..e9f3c0476 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Po vymazání výběru obrazovky můžete znovu vybrat obrazovku, kterou chcete sdílet."), ("confirm_clear_Wayland_screen_selection_tip", "Opravdu chcete vymazat výběr obrazovky Wayland?"), ("android_new_voice_call_tip", "Byl přijat nový požadavek na hlasové volání. Pokud hovor přijmete, přepne se zvuk na hlasovou komunikaci."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 503567072..c68df391c 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 9e299b12e..1901e0bfb 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Nachdem Sie die Bildschirmauswahl gelöscht haben, können Sie den freizugebenden Bildschirm erneut auswählen."), ("confirm_clear_Wayland_screen_selection_tip", "Sind Sie sicher, dass Sie die Auswahl des Wayland-Bildschirms löschen möchten?"), ("android_new_voice_call_tip", "Eine neue Sprachanrufanfrage wurde empfangen. Wenn Sie die Anfrage annehmen, wird der Ton auf Sprachkommunikation umgeschaltet."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index ac08f3efb..f1a2ad736 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index 25438ee65..7a1617757 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -228,5 +228,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "After clearing the screen selection, you can reselect the screen to share."), ("confirm_clear_Wayland_screen_selection_tip", "Are you sure to clear the Wayland screen selection?"), ("android_new_voice_call_tip", "A new voice call request was received. If you accept, the audio will switch to voice communication."), + ("texture_render_tip", "Use texture rendering to make the pictures smoother."), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index fc85b75b3..e4376565a 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 4f713ec5f..b9dfdb30d 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Tras borrar la selección de pantalla, puedes volver a seleccionarla para compartir."), ("confirm_clear_Wayland_screen_selection_tip", "¿Seguro que deseas borrar la selección de pantalla Wayland?"), ("android_new_voice_call_tip", "Se ha recibido una nueva solicitud de llamada de voz. Si aceptas el audio cambiará a comunicación de voz."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index 09535549a..3c4786900 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index e8080a191..2ebec3f38 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "پس از پاک کردن صفحه انتخابی، می توانید صفحه را برای اشتراک گذاری مجدد انتخاب کنید"), ("confirm_clear_Wayland_screen_selection_tip", "را پاک می کنید؟ Wayland آیا مطمئن هستید که انتخاب صفحه"), ("android_new_voice_call_tip", "یک درخواست تماس صوتی جدید دریافت شد. اگر بپذیرید، صدا به ارتباط صوتی تغییر خواهد کرد."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 05d03f43b..0a1c0c2df 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/he.rs b/src/lang/he.rs index 881a2c158..911960e11 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hr.rs b/src/lang/hr.rs index 9f91e226a..5d1fff798 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 28020432e..1f5899919 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 6bcba2f76..fe85beb70 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 44c8dc973..904a85c68 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Dopo aver annullato la selezione schermo, è possibile selezionare nuovamente lo schermo da condividere."), ("confirm_clear_Wayland_screen_selection_tip", "Sei sicuro di voler annullare la selezione schermo Wayland?"), ("android_new_voice_call_tip", "È stata ricevuta una nuova richiesta di chiamata vocale. Se accetti, l'audio passerà alla comunicazione vocale."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index f90f485c4..27115c308 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index e67ae4552..a35bbcbcb 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 022fc3d79..b93558eb1 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index ae154bc6a..44bcafb82 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index d1858e605..b673195c8 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Pēc ekrāna atlases notīrīšanas varat atkārtoti atlasīt ekrānu, ko kopīgot."), ("confirm_clear_Wayland_screen_selection_tip", "Vai tiešām notīrīt Wayland ekrāna atlasi?"), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index ce52a9aa6..7428c2cae 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index c8281ee3c..0ab9188f8 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Nadat je de schermselectie hebt gewist, kun je het scherm dat je wilt delen opnieuw selecteren."), ("confirm_clear_Wayland_screen_selection_tip", "Weet je zeker dat je de Wayland-schermselectie wilt wissen?"), ("android_new_voice_call_tip", "Er is een nieuwe spraakoproep ontvangen. Als u het aanvaardt, schakelt de audio over naar spraakcommunicatie."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index a2a054a95..3334d1619 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index e5e6c252b..86c98df45 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 53624c288..667528c5d 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 73eea0c6c..f17d93b39 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index c14286e78..3273f1ac6 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "После отмены можно заново выбрать экран для демонстрации."), ("confirm_clear_Wayland_screen_selection_tip", "Отменить выбор экрана Wayland?"), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 2bd403dbb..844a8eaab 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Po vymazaní výberu obrazovky môžete znova vybrať obrazovku, ktorú chcete zdieľať."), ("confirm_clear_Wayland_screen_selection_tip", "Určite ste si istý, že chcete vyčistiť výber obrazovky Wayland?"), ("android_new_voice_call_tip", "Bola prijatá nová žiadosť o hlasový hovor. Ak ho prijmete, zvuk sa prepne na hlasovú komunikáciu."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 352548e0e..f6c9581f2 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index acb149fa8..33dfc62d7 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 901010120..fbfb461c1 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 400a00315..f47da81dd 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 816618717..4f702fc79 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index dca9cd8bc..c74b1c4dc 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 5d5d2388e..0dced6a43 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 88400d78b..a99eb1648 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "清除 Wayland 的螢幕選擇後,您可以重新選擇分享的螢幕。"), ("confirm_clear_Wayland_screen_selection_tip", "是否確認清除 Wayland 的分享螢幕選擇?"), ("android_new_voice_call_tip", "收到新的語音通話請求。如果您接受,音訊將切換為語音通訊。"), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 72e1c82b3..19a5ad6aa 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", "Після очищення вибору екрана ви можете повторно вибрати екран для поширення."), ("confirm_clear_Wayland_screen_selection_tip", "Ви впевнені, що хочете очистити вибір екрана Wayland?"), ("android_new_voice_call_tip", "Отримано новий запит на голосовий дзвінок. Якщо ви приймете його, аудіо перемкнеться на голосовий звʼязок."), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index ea10f50ff..6cf389a3f 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""), ("android_new_voice_call_tip", ""), + ("texture_render_tip", ""), + ("Use texture rendering", ""), ].iter().cloned().collect(); } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 0431e0dbb..dd4c6fe45 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -53,7 +53,7 @@ use scrap::{ codec::{Encoder, EncoderCfg, Quality}, record::{Recorder, RecorderContext}, vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, - CodecFormat, Display, EncodeInput, Frame, TraitCapturer, + CodecFormat, Display, EncodeInput, TraitCapturer, }; #[cfg(windows)] use std::sync::Once; diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 452478e2e..b58ed6bb3 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -169,6 +169,26 @@ pub fn get_option>(key: T) -> String { } } +#[inline] +#[cfg(target_os = "macos")] +pub fn use_texture_render() -> bool { + cfg!(feature = "flutter") + && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) == "Y" +} + +#[inline] +#[cfg(any(target_os = "windows", target_os = "linux"))] +pub fn use_texture_render() -> bool { + cfg!(feature = "flutter") + && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) != "N" +} + +#[inline] +#[cfg(any(target_os = "android", target_os = "ios"))] +pub fn use_texture_render() -> bool { + false +} + #[inline] pub fn get_local_option(key: String) -> String { LocalConfig::get_option(&key) @@ -898,7 +918,8 @@ pub fn has_vram() -> bool { #[cfg(feature = "flutter")] #[inline] pub fn supported_hwdecodings() -> (bool, bool) { - let decoding = scrap::codec::Decoder::supported_decodings(None, true, None, &vec![]); + let decoding = + scrap::codec::Decoder::supported_decodings(None, use_texture_render(), None, &vec![]); #[allow(unused_mut)] let (mut h264, mut h265) = (decoding.ability_h264 > 0, decoding.ability_h265 > 0); #[cfg(feature = "vram")] diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 56ddbaf59..969221f78 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1,6 +1,7 @@ use crate::{ common::{get_supported_keyboard_modes, is_keyboard_mode_supported}, input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL}, + ui_interface::use_texture_render, }; use async_trait::async_trait; use bytes::Bytes; @@ -448,7 +449,7 @@ impl Session { let mark_unsupported = self.lc.read().unwrap().mark_unsupported.clone(); let decoder = scrap::codec::Decoder::supported_decodings( None, - cfg!(feature = "flutter"), + use_texture_render(), luid, &mark_unsupported, ); @@ -469,6 +470,11 @@ impl Session { self.send(Data::Message(msg)); } + pub fn use_texture_render_changed(&self) { + self.send(Data::ResetDecoder(None)); + self.change_prefer_codec(); + } + pub fn restart_remote_device(&self) { let mut lc = self.lc.write().unwrap(); lc.restarting_remote_device = true; @@ -732,8 +738,7 @@ impl Session { msg_out.set_misc(misc); self.send(Data::Message(msg_out)); - #[cfg(not(feature = "flutter_texture_render"))] - { + if !use_texture_render() { self.capture_displays(vec![], vec![], vec![display]); } }