refact: texture render as an option (#8168)

* refact: texture render as an option

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: texture render, translation

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: texture render as option

Signed-off-by: fufesou <linlong1266@gmail.com>

* Update ui_interface.rs

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
This commit is contained in:
fufesou 2024-05-28 16:42:30 +08:00 committed by GitHub
parent 010b17509a
commit 72ec86b58d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 481 additions and 282 deletions

View File

@ -548,13 +548,14 @@ jobs:
- { - {
target: x86_64-apple-darwin, 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 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, arch: x86_64,
} }
- { - {
target: aarch64-apple-darwin, target: aarch64-apple-darwin,
os: macos-latest, 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, arch: aarch64,
} }
steps: steps:
@ -1124,7 +1125,7 @@ jobs:
export JOBS="" export JOBS=""
fi fi
echo $JOBS 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 target/release/deps target/release/build
rm -rf ~/.cargo rm -rf ~/.cargo

View File

@ -19,7 +19,6 @@ path = "src/naming.rs"
[features] [features]
inline = [] inline = []
cli = [] cli = []
flutter_texture_render = []
use_samplerate = ["samplerate"] use_samplerate = ["samplerate"]
use_rubato = ["rubato"] use_rubato = ["rubato"]
use_dasp = ["dasp"] use_dasp = ["dasp"]

View File

@ -111,8 +111,6 @@ def make_parser():
'Available: PrivacyMode. Special value is "ALL" and empty "". Default is empty.') 'Available: PrivacyMode. Special value is "ALL" and empty "". Default is empty.')
parser.add_argument('--flutter', action='store_true', parser.add_argument('--flutter', action='store_true',
help='Build flutter package', default=False) 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( parser.add_argument(
'--hwcodec', '--hwcodec',
action='store_true', action='store_true',
@ -278,8 +276,6 @@ def get_features(args):
features.append('vram') features.append('vram')
if args.flutter: if args.flutter:
features.append('flutter') features.append('flutter')
if not args.disable_flutter_texture_render:
features.append('flutter_texture_render')
if args.unix_file_copy_paste: if args.unix_file_copy_paste:
features.append('unix-file-copy-paste') features.append('unix-file-copy-paste')
print("features:", features) print("features:", features)

View File

@ -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/refresh_wrapper.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/main.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/peer_model.dart';
import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/utils/multi_window_manager.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<List<Rect>> getScreenListWayland() async { Future<List<Rect>> getScreenListWayland() async {
final screenRectList = <Rect>[]; final screenRectList = <Rect>[];
if (isMainDesktopWindow) { if (isMainDesktopWindow) {

View File

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/consts.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:flutter_hbb/models/platform_model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -227,8 +226,7 @@ List<(String, String)> otherDefaultSettings() {
if ((isDesktop || isWebDesktop)) ('Zoom cursor', kOptionZoomCursor), if ((isDesktop || isWebDesktop)) ('Zoom cursor', kOptionZoomCursor),
('Show quality monitor', kOptionShowQualityMonitor), ('Show quality monitor', kOptionShowQualityMonitor),
('Mute', kOptionDisableAudio), ('Mute', kOptionDisableAudio),
if (isDesktop) if (isDesktop) ('Enable file copy and paste', kOptionEnableFileCopyPaste),
('Enable file copy and paste', kOptionEnableFileCopyPaste),
('Disable clipboard', kOptionDisableClipboard), ('Disable clipboard', kOptionDisableClipboard),
('Lock after session end', kOptionLockAfterSessionEnd), ('Lock after session end', kOptionLockAfterSessionEnd),
('Privacy mode', kOptionPrivacyMode), ('Privacy mode', kOptionPrivacyMode),
@ -236,12 +234,12 @@ List<(String, String)> otherDefaultSettings() {
('True color (4:4:4)', kOptionI444), ('True color (4:4:4)', kOptionI444),
('Reverse mouse wheel', kKeyReverseMouseWheel), ('Reverse mouse wheel', kKeyReverseMouseWheel),
('swap-left-right-mouse', kOptionSwapLeftRightMouse), ('swap-left-right-mouse', kOptionSwapLeftRightMouse),
if (isDesktop && useTextureRender) if (isDesktop && bind.mainGetUseTextureRender())
( (
'Show displays as individual windows', 'Show displays as individual windows',
kKeyShowDisplaysAsIndividualWindows kKeyShowDisplaysAsIndividualWindows
), ),
if (isDesktop && useTextureRender) if (isDesktop && bind.mainGetUseTextureRender())
( (
'Use all my displays for the remote session', 'Use all my displays for the remote session',
kKeyUseAllMyDisplaysForTheRemoteSession kKeyUseAllMyDisplaysForTheRemoteSession

View File

@ -8,7 +8,6 @@ import 'package:flutter_hbb/common/widgets/dialog.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_hbb/models/model.dart';
import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/platform_model.dart';
import 'package:flutter_hbb/models/desktop_render_texture.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
bool isEditOsPassword = false; bool isEditOsPassword = false;
@ -581,7 +580,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
child: Text(translate('Lock after session end')))); child: Text(translate('Lock after session end'))));
} }
if (useTextureRender && if (bind.mainGetUseTextureRender() &&
pi.isSupportMultiDisplay && pi.isSupportMultiDisplay &&
PrivacyModeState.find(id).isEmpty && PrivacyModeState.find(id).isEmpty &&
pi.displaysCount.value > 1 && pi.displaysCount.value > 1 &&
@ -600,7 +599,9 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
} }
final isMultiScreens = !isWeb && (await getScreenRectList()).length > 1; final isMultiScreens = !isWeb && (await getScreenRectList()).length > 1;
if (useTextureRender && pi.isSupportMultiDisplay && isMultiScreens) { if (bind.mainGetUseTextureRender() &&
pi.isSupportMultiDisplay &&
isMultiScreens) {
final value = bind.sessionGetUseAllMyDisplaysForTheRemoteSession( final value = bind.sessionGetUseAllMyDisplaysForTheRemoteSession(
sessionId: ffi.sessionId) == sessionId: ffi.sessionId) ==
'Y'; 'Y';

View File

@ -73,6 +73,7 @@ const String kOptionViewStyle = "view_style";
const String kOptionScrollStyle = "scroll_style"; const String kOptionScrollStyle = "scroll_style";
const String kOptionImageQuality = "image_quality"; const String kOptionImageQuality = "image_quality";
const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs"; const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
const String kOptionTextureRender = "use-texture-render";
const String kOptionOpenInTabs = "allow-open-in-tabs"; const String kOptionOpenInTabs = "allow-open-in-tabs";
const String kOptionOpenInWindows = "allow-open-in-windows"; const String kOptionOpenInWindows = "allow-open-in-windows";
const String kOptionForceAlwaysRelay = "force-always-relay"; const String kOptionForceAlwaysRelay = "force-always-relay";
@ -153,6 +154,8 @@ const String kKeyUseAllMyDisplaysForTheRemoteSession =
const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar'; const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar';
const String kKeyReverseMouseWheel = "reverse_mouse_wheel"; const String kKeyReverseMouseWheel = "reverse_mouse_wheel";
const String kMsgboxTextWaitingForImage = 'Connected, waiting for image...';
// the executable name of the portable version // the executable name of the portable version
const String kEnvPortableExecutable = "RUSTDESK_APPNAME"; const String kEnvPortableExecutable = "RUSTDESK_APPNAME";

View File

@ -387,10 +387,25 @@ class _GeneralState extends State<_General> {
isServer: false, isServer: false,
), ),
// though this is related to GUI, but opengl problem affects all users, so put in config rather than local // 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( Tooltip(
message: translate('software_render_tip'), message: translate('texture_render_tip'),
child: _OptionCheckBox(context, "Always use software rendering", child: _OptionCheckBox(
kOptionAllowAlwaysSoftwareRender), context,
"Use texture rendering",
kOptionTextureRender,
optGetter: bind.mainGetUseTextureRender,
optSetter: (k, v) async =>
await bind.mainSetLocalOption(key: k, value: v ? 'Y' : 'N'),
),
), ),
if (!bind.isCustomClient()) if (!bind.isCustomClient())
_OptionCheckBox( _OptionCheckBox(
@ -426,7 +441,7 @@ class _GeneralState extends State<_General> {
context, context,
'Remove wallpaper during incoming sessions', 'Remove wallpaper during incoming sessions',
kOptionAllowRemoveWallpaper, kOptionAllowRemoveWallpaper,
update: () { update: (bool v) {
setState(() {}); setState(() {});
}, },
), ),
@ -457,8 +472,8 @@ class _GeneralState extends State<_General> {
context, context,
'Enable hardware codec', 'Enable hardware codec',
kOptionEnableHwcodec, kOptionEnableHwcodec,
update: () { update: (bool v) {
if (mainGetBoolOptionSync(kOptionEnableHwcodec)) { if (v) {
bind.mainCheckHwcodec(); bind.mainCheckHwcodec();
} }
}, },
@ -941,7 +956,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
List<Widget> directIp(BuildContext context) { List<Widget> directIp(BuildContext context) {
TextEditingController controller = TextEditingController(); TextEditingController controller = TextEditingController();
update() => setState(() {}); update(bool v) => setState(() {});
RxBool applyEnabled = false.obs; RxBool applyEnabled = false.obs;
return [ return [
_OptionCheckBox(context, 'Enable direct IP access', kOptionDirectServer, _OptionCheckBox(context, 'Enable direct IP access', kOptionDirectServer,
@ -1102,7 +1117,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
List<Widget> autoDisconnect(BuildContext context) { List<Widget> autoDisconnect(BuildContext context) {
TextEditingController controller = TextEditingController(); TextEditingController controller = TextEditingController();
update() => setState(() {}); update(bool v) => setState(() {});
RxBool applyEnabled = false.obs; RxBool applyEnabled = false.obs;
return [ return [
_OptionCheckBox( _OptionCheckBox(
@ -1803,33 +1818,41 @@ Widget _Card(
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Widget _OptionCheckBox(BuildContext context, String label, String key, Widget _OptionCheckBox(
{Function()? update, BuildContext context,
bool reverse = false, String label,
bool enabled = true, String key, {
Icon? checkedIcon, Function(bool)? update,
bool? fakeValue, bool reverse = false,
bool isServer = true}) { bool enabled = true,
bool value = Icon? checkedIcon,
isServer ? mainGetBoolOptionSync(key) : mainGetLocalBoolOptionSync(key); bool? fakeValue,
bool isServer = true,
bool Function()? optGetter,
Future<void> Function(String, bool)? optSetter,
}) {
getOpt() => optGetter != null
? optGetter()
: (isServer
? mainGetBoolOptionSync(key)
: mainGetLocalBoolOptionSync(key));
bool value = getOpt();
final isOptFixed = isOptionFixed(key); final isOptFixed = isOptionFixed(key);
if (reverse) value = !value; if (reverse) value = !value;
var ref = value.obs; var ref = value.obs;
onChanged(option) async { onChanged(option) async {
if (option != null) { if (option != null) {
if (reverse) option = !option; if (reverse) option = !option;
isServer final setter =
? await mainSetBoolOption(key, option) optSetter ?? (isServer ? mainSetBoolOption : mainSetLocalBoolOption);
: await mainSetLocalBoolOption(key, option); await setter(key, option);
final readOption = isServer final readOption = getOpt();
? mainGetBoolOptionSync(key)
: mainGetLocalBoolOptionSync(key);
if (reverse) { if (reverse) {
ref.value = !readOption; ref.value = !readOption;
} else { } else {
ref.value = readOption; ref.value = readOption;
} }
update?.call(); update?.call(readOption);
} }
} }

View File

@ -16,7 +16,6 @@ import '../../common.dart';
import '../../common/widgets/dialog.dart'; import '../../common/widgets/dialog.dart';
import '../../common/widgets/toolbar.dart'; import '../../common/widgets/toolbar.dart';
import '../../models/model.dart'; import '../../models/model.dart';
import '../../models/desktop_render_texture.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
import '../../common/shared_state.dart'; import '../../common/shared_state.dart';
import '../../utils/image.dart'; import '../../utils/image.dart';
@ -593,12 +592,11 @@ class _ImagePaintState extends State<ImagePaint> {
onHover: (evt) {}, onHover: (evt) {},
child: child); child: child);
}); });
if (c.imageOverflow.isTrue && c.scrollStyle == ScrollStyle.scrollbar) { if (c.imageOverflow.isTrue && c.scrollStyle == ScrollStyle.scrollbar) {
final paintWidth = c.getDisplayWidth() * s; final paintWidth = c.getDisplayWidth() * s;
final paintHeight = c.getDisplayHeight() * s; final paintHeight = c.getDisplayHeight() * s;
final paintSize = Size(paintWidth, paintHeight); final paintSize = Size(paintWidth, paintHeight);
final paintWidget = useTextureRender final paintWidget = m.useTextureRender
? _BuildPaintTextureRender( ? _BuildPaintTextureRender(
c, s, Offset.zero, paintSize, isViewOriginal()) c, s, Offset.zero, paintSize, isViewOriginal())
: _buildScrollbarNonTextureRender(m, paintSize, s); : _buildScrollbarNonTextureRender(m, paintSize, s);
@ -619,7 +617,7 @@ class _ImagePaintState extends State<ImagePaint> {
)); ));
} else { } else {
if (c.size.width > 0 && c.size.height > 0) { if (c.size.width > 0 && c.size.height > 0) {
final paintWidget = useTextureRender final paintWidget = m.useTextureRender
? _BuildPaintTextureRender( ? _BuildPaintTextureRender(
c, c,
s, s,

View File

@ -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/common/widgets/toolbar.dart';
import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/chat_model.dart';
import 'package:flutter_hbb/models/state_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/consts.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_hbb/plugin/widgets/desc_ui.dart'; import 'package:flutter_hbb/plugin/widgets/desc_ui.dart';
@ -615,14 +614,14 @@ class _MonitorMenu extends StatelessWidget {
bind.mainGetUserDefaultOption(key: kKeyShowMonitorsToolbar) == 'Y'; bind.mainGetUserDefaultOption(key: kKeyShowMonitorsToolbar) == 'Y';
bool get supportIndividualWindows => bool get supportIndividualWindows =>
useTextureRender && ffi.ffiModel.pi.isSupportMultiDisplay; !isWeb && ffi.ffiModel.pi.isSupportMultiDisplay;
@override @override
Widget build(BuildContext context) => showMonitorsToolbar Widget build(BuildContext context) => showMonitorsToolbar
? buildMultiMonitorMenu() ? buildMultiMonitorMenu(context)
: Obx(() => buildMonitorMenu()); : Obx(() => buildMonitorMenu(context));
Widget buildMonitorMenu() { Widget buildMonitorMenu(BuildContext context) {
final width = SimpleWrapper<double>(0); final width = SimpleWrapper<double>(0);
final monitorsIcon = final monitorsIcon =
globalMonitorsWidget(width, Colors.white, Colors.black38); globalMonitorsWidget(width, Colors.white, Colors.black38);
@ -636,20 +635,23 @@ class _MonitorMenu extends StatelessWidget {
menuStyle: MenuStyle( menuStyle: MenuStyle(
padding: padding:
MaterialStatePropertyAll(EdgeInsets.symmetric(horizontal: 6))), MaterialStatePropertyAll(EdgeInsets.symmetric(horizontal: 6))),
menuChildrenGetter: () => [buildMonitorSubmenuWidget()]); menuChildrenGetter: () => [buildMonitorSubmenuWidget(context)]);
} }
Widget buildMultiMonitorMenu() { Widget buildMultiMonitorMenu(BuildContext context) {
return Row(children: buildMonitorList(true)); return Row(children: buildMonitorList(context, true));
} }
Widget buildMonitorSubmenuWidget() { Widget buildMonitorSubmenuWidget(BuildContext context) {
final m = Provider.of<ImageModel>(context);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Row(children: buildMonitorList(false)), Row(children: buildMonitorList(context, false)),
supportIndividualWindows ? Divider() : Offstage(), supportIndividualWindows && m.useTextureRender ? Divider() : Offstage(),
supportIndividualWindows ? chooseDisplayBehavior() : Offstage(), supportIndividualWindows && m.useTextureRender
? chooseDisplayBehavior()
: Offstage(),
], ],
); );
} }
@ -680,7 +682,7 @@ class _MonitorMenu extends StatelessWidget {
), ),
); );
List<Widget> buildMonitorList(bool isMulti) { List<Widget> buildMonitorList(BuildContext context, bool isMulti) {
final List<Widget> monitorList = []; final List<Widget> monitorList = [];
final pi = ffi.ffiModel.pi; final pi = ffi.ffiModel.pi;
@ -735,7 +737,10 @@ class _MonitorMenu extends StatelessWidget {
for (int i = 0; i < pi.displays.length; i++) { for (int i = 0; i < pi.displays.length; i++) {
monitorList.add(buildMonitorButton(i)); monitorList.add(buildMonitorButton(i));
} }
if (supportIndividualWindows && pi.displays.length > 1) { final m = Provider.of<ImageModel>(context);
if (supportIndividualWindows &&
m.useTextureRender &&
pi.displays.length > 1) {
monitorList.add(buildMonitorButton(kAllDisplayValue)); monitorList.add(buildMonitorButton(kAllDisplayValue));
} }
return monitorList; return monitorList;
@ -818,7 +823,12 @@ class _MonitorMenu extends StatelessWidget {
} }
RxInt display = CurrentDisplayState.find(id); RxInt display = CurrentDisplayState.find(id);
if (display.value != i) { 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); openMonitorInNewTabOrWindow(i, ffi.id, pi);
} else { } else {
openMonitorInTheSameTab(i, ffi, pi, updateCursorPos: !isMulti); openMonitorInTheSameTab(i, ffi, pi, updateCursorPos: !isMulti);

View File

@ -11,15 +11,10 @@ import './platform_model.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart' import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'
if (dart.library.html) 'package:flutter_hbb/web/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 { class _PixelbufferTexture {
int _textureKey = -1; int _textureKey = -1;
int _display = 0; int _display = 0;
SessionID? _sessionId; SessionID? _sessionId;
final support = bind.mainHasPixelbufferTextureRender();
bool _destroying = false; bool _destroying = false;
int? _id; int? _id;
@ -28,26 +23,24 @@ class _PixelbufferTexture {
int get display => _display; int get display => _display;
create(int d, SessionID sessionId, FFI ffi) { create(int d, SessionID sessionId, FFI ffi) {
if (support) { _display = d;
_display = d; _textureKey = bind.getNextTextureKey();
_textureKey = bind.getNextTextureKey(); _sessionId = sessionId;
_sessionId = sessionId;
textureRenderer.createTexture(_textureKey).then((id) async { textureRenderer.createTexture(_textureKey).then((id) async {
_id = id; _id = id;
if (id != -1) { if (id != -1) {
ffi.textureModel.setRgbaTextureId(display: d, id: id); ffi.textureModel.setRgbaTextureId(display: d, id: id);
final ptr = await textureRenderer.getTexturePtr(_textureKey); final ptr = await textureRenderer.getTexturePtr(_textureKey);
platformFFI.registerPixelbufferTexture(sessionId, display, ptr); platformFFI.registerPixelbufferTexture(sessionId, display, ptr);
debugPrint( debugPrint(
"create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr"); "create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr");
} }
}); });
}
} }
destroy(bool unregisterTexture, FFI ffi) async { destroy(bool unregisterTexture, FFI ffi) async {
if (!_destroying && support && _textureKey != -1 && _sessionId != null) { if (!_destroying && _textureKey != -1 && _sessionId != null) {
_destroying = true; _destroying = true;
if (unregisterTexture) { if (unregisterTexture) {
platformFFI.registerPixelbufferTexture(_sessionId!, display, 0); platformFFI.registerPixelbufferTexture(_sessionId!, display, 0);

View File

@ -244,7 +244,7 @@ class FfiModel with ChangeNotifier {
handleMsgBox({ handleMsgBox({
'type': 'success', 'type': 'success',
'title': 'Successful', 'title': 'Successful',
'text': 'Connected, waiting for image...', 'text': kMsgboxTextWaitingForImage,
'link': '', 'link': '',
}, sessionId, peerId); }, sessionId, peerId);
updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId); updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId);
@ -380,12 +380,22 @@ class FfiModel with ChangeNotifier {
_handleSyncPeerOption(evt, peerId); _handleSyncPeerOption(evt, peerId);
} else if (name == 'follow_current_display') { } else if (name == 'follow_current_display') {
handleFollowCurrentDisplay(evt, sessionId, peerId); handleFollowCurrentDisplay(evt, sessionId, peerId);
} else if (name == 'use_texture_render') {
_handleUseTextureRender(evt, sessionId, peerId);
} else { } else {
debugPrint('Unknown event name: $name'); debugPrint('Unknown event name: $name');
} }
}; };
} }
_handleUseTextureRender(
Map<String, dynamic> 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<String, dynamic> evt, String peer) { _handleSyncPeerOption(Map<String, dynamic> evt, String peer) {
final k = evt['k']; final k = evt['k'];
final v = evt['v']; final v = evt['v'];
@ -572,7 +582,7 @@ class FfiModel with ChangeNotifier {
showElevationError(sessionId, type, title, text, dialogManager); showElevationError(sessionId, type, title, text, dialogManager);
} else if (type == 'relay-hint' || type == 'relay-hint2') { } else if (type == 'relay-hint' || type == 'relay-hint2') {
showRelayHintDialog(sessionId, type, title, text, dialogManager, peerId); showRelayHintDialog(sessionId, type, title, text, dialogManager, peerId);
} else if (text == 'Connected, waiting for image...') { } else if (text == kMsgboxTextWaitingForImage) {
showConnectedWaitingForImage(dialogManager, sessionId, type, title, text); showConnectedWaitingForImage(dialogManager, sessionId, type, title, text);
} else if (title == 'Privacy mode') { } else if (title == 'Privacy mode') {
final hasRetry = evt['hasRetry'] == 'true'; final hasRetry = evt['hasRetry'] == 'true';
@ -1156,6 +1166,8 @@ class ImageModel with ChangeNotifier {
late final SessionID sessionId; late final SessionID sessionId;
bool _useTextureRender = false;
WeakReference<FFI> parent; WeakReference<FFI> parent;
final List<Function(String)> callbacksOnFirstImage = []; final List<Function(String)> callbacksOnFirstImage = [];
@ -1164,6 +1176,8 @@ class ImageModel with ChangeNotifier {
sessionId = parent.target!.sessionId; sessionId = parent.target!.sessionId;
} }
get useTextureRender => _useTextureRender;
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb); addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
onRgba(int display, Uint8List rgba) { onRgba(int display, Uint8List rgba) {
@ -1233,6 +1247,19 @@ class ImageModel with ChangeNotifier {
return min(xscale, yscale) / 1.5; 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() { void disposeImage() {
_image?.dispose(); _image?.dispose();
_image = null; _image = null;
@ -2387,7 +2414,7 @@ class FFI {
sessionId: sessionId, displays: Int32List.fromList(displays)); sessionId: sessionId, displays: Int32List.fromList(displays));
ffiModel.pi.currentDisplay = display; ffiModel.pi.currentDisplay = display;
} }
if (connType == ConnType.defaultConn && useTextureRender) { if (isDesktop && connType == ConnType.defaultConn) {
textureModel.updateCurrentDisplay(display ?? 0); textureModel.updateCurrentDisplay(display ?? 0);
} }
final stream = bind.sessionStart(sessionId: sessionId, id: id); 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 hasGpuTextureRender = bind.mainHasGpuTextureRender();
final SimpleWrapper<bool> isToNewWindowNotified = SimpleWrapper(false); final SimpleWrapper<bool> isToNewWindowNotified = SimpleWrapper(false);
// Preserved for the rgba data. // Preserved for the rgba data.
stream.listen((message) { stream.listen((message) {
@ -2460,7 +2486,7 @@ class FFI {
} }
} else if (message is EventToUI_Rgba) { } else if (message is EventToUI_Rgba) {
final display = message.field0; final display = message.field0;
if (hasPixelBufferTextureRender) { if (imageModel.useTextureRender) {
debugPrint("EventToUI_Rgba display:$display"); debugPrint("EventToUI_Rgba display:$display");
textureModel.setTextureType(display: display, gpuTexture: false); textureModel.setTextureType(display: display, gpuTexture: false);
onEvent2UIRgba(); onEvent2UIRgba();

View File

@ -1414,10 +1414,6 @@ class RustdeskImpl {
throw UnimplementedError(); throw UnimplementedError();
} }
bool mainHasPixelbufferTextureRender({dynamic hint}) {
return false;
}
bool mainHasFileClipboard({dynamic hint}) { bool mainHasFileClipboard({dynamic hint}) {
return false; return false;
} }
@ -1608,5 +1604,9 @@ class RustdeskImpl {
throw UnimplementedError(); throw UnimplementedError();
} }
bool mainGetUseTextureRender({dynamic hint}) {
throw UnimplementedError();
}
void dispose() {} void dispose() {}
} }

View File

@ -2053,6 +2053,7 @@ pub mod keys {
pub const OPTION_ENABLE_CONFIRM_CLOSING_TABS: &str = "enable-confirm-closing-tabs"; pub const OPTION_ENABLE_CONFIRM_CLOSING_TABS: &str = "enable-confirm-closing-tabs";
pub const OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS: &str = pub const OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS: &str =
"enable-open-new-connections-in-tabs"; "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_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_WITH_RECENT_SESSIONS: &str = "sync-ab-with-recent-sessions";
pub const OPTION_SYNC_AB_TAGS: &str = "sync-ab-tags"; pub const OPTION_SYNC_AB_TAGS: &str = "sync-ab-tags";
@ -2133,6 +2134,7 @@ pub mod keys {
OPTION_LANGUAGE, OPTION_LANGUAGE,
OPTION_ENABLE_CONFIRM_CLOSING_TABS, OPTION_ENABLE_CONFIRM_CLOSING_TABS,
OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS, OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS,
OPTION_TEXTURE_RENDER,
OPTION_SYNC_AB_WITH_RECENT_SESSIONS, OPTION_SYNC_AB_WITH_RECENT_SESSIONS,
OPTION_SYNC_AB_TAGS, OPTION_SYNC_AB_TAGS,
OPTION_FILTER_AB_BY_INTERSECTION, OPTION_FILTER_AB_BY_INTERSECTION,

View File

@ -419,7 +419,7 @@ impl Encoder {
impl Decoder { impl Decoder {
pub fn supported_decodings( pub fn supported_decodings(
id_for_perfer: Option<&str>, id_for_perfer: Option<&str>,
_flutter: bool, _use_texture_render: bool,
_luid: Option<i64>, _luid: Option<i64>,
mark_unsupported: &Vec<CodecFormat>, mark_unsupported: &Vec<CodecFormat>,
) -> SupportedDecoding { ) -> SupportedDecoding {
@ -454,7 +454,7 @@ impl Decoder {
}; };
} }
#[cfg(feature = "vram")] #[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 { decoding.ability_h264 |= if VRamDecoder::available(CodecFormat::H264, _luid).len() > 0 {
1 1
} else { } else {

View File

@ -88,6 +88,11 @@ impl ImageRgb {
pub fn stride(&self) -> usize { pub fn stride(&self) -> usize {
self.stride self.stride
} }
#[inline]
pub fn set_stride(&mut self, stride: usize) {
self.stride = stride;
}
} }
#[inline] #[inline]

View File

@ -39,7 +39,7 @@ use hbb_common::{
}, },
get_version_number, log, get_version_number, log,
message_proto::{option_message::BoolOption, *}, message_proto::{option_message::BoolOption, *},
protobuf::Message as _, protobuf::{Message as _, MessageField},
rand, rand,
rendezvous_proto::*, rendezvous_proto::*,
socket_client, socket_client,
@ -61,6 +61,7 @@ use crate::{
check_port, check_port,
common::input::{MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP}, 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, 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}, ui_session_interface::{InvokeUiSession, Session},
}; };
@ -1035,16 +1036,23 @@ pub struct VideoHandler {
} }
impl VideoHandler { impl VideoHandler {
#[cfg(feature = "flutter")]
pub fn get_adapter_luid() -> Option<i64> {
crate::flutter::get_adapter_luid()
}
#[cfg(not(feature = "flutter"))]
pub fn get_adapter_luid() -> Option<i64> {
None
}
/// Create a new video handler. /// Create a new video handler.
pub fn new(format: CodecFormat, _display: usize) -> Self { pub fn new(format: CodecFormat, _display: usize) -> Self {
#[cfg(all(feature = "vram", feature = "flutter"))] let luid = Self::get_adapter_luid();
let luid = crate::flutter::get_adapter_luid();
#[cfg(not(all(feature = "vram", feature = "flutter")))]
let luid = Default::default();
log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}"); log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}");
VideoHandler { VideoHandler {
decoder: Decoder::new(format, luid), 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(), texture: std::ptr::null_mut(),
recorder: Default::default(), recorder: Default::default(),
record: false, record: false,
@ -1096,10 +1104,9 @@ impl VideoHandler {
/// Reset the decoder, change format if it is Some /// Reset the decoder, change format if it is Some
pub fn reset(&mut self, format: Option<CodecFormat>) { pub fn reset(&mut self, format: Option<CodecFormat>) {
#[cfg(all(feature = "flutter", feature = "vram"))] #[cfg(target_os = "macos")]
let luid = crate::flutter::get_adapter_luid(); self.rgb.set_stride(crate::get_dst_stride_rgba());
#[cfg(not(all(feature = "flutter", feature = "vram")))] let luid = Self::get_adapter_luid();
let luid = None;
let format = format.unwrap_or(self.decoder.format()); let format = format.unwrap_or(self.decoder.format());
self.decoder = Decoder::new(format, luid); self.decoder = Decoder::new(format, luid);
self.fail_counter = 0; self.fail_counter = 0;
@ -1637,16 +1644,19 @@ impl LoginConfigHandler {
if view_only || self.get_toggle_option("disable-clipboard") { if view_only || self.get_toggle_option("disable-clipboard") {
msg.disable_clipboard = BoolOption::Yes.into(); msg.disable_clipboard = BoolOption::Yes.into();
} }
msg.supported_decoding = msg.supported_decoding = MessageField::some(self.get_supported_decoding());
hbb_common::protobuf::MessageField::some(Decoder::supported_decodings(
Some(&self.id),
cfg!(feature = "flutter"),
self.adapter_luid,
&self.mark_unsupported,
));
Some(msg) 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<OptionMessage> { pub fn get_option_message_after_login(&self) -> Option<OptionMessage> {
if self.conn_type.eq(&ConnType::FILE_TRANSFER) if self.conn_type.eq(&ConnType::FILE_TRANSFER)
|| self.conn_type.eq(&ConnType::PORT_FORWARD) || self.conn_type.eq(&ConnType::PORT_FORWARD)
@ -2036,7 +2046,7 @@ impl LoginConfigHandler {
pub fn update_supported_decodings(&self) -> Message { pub fn update_supported_decodings(&self) -> Message {
let decoding = scrap::codec::Decoder::supported_decodings( let decoding = scrap::codec::Decoder::supported_decodings(
Some(&self.id), Some(&self.id),
cfg!(feature = "flutter"), use_texture_render(),
self.adapter_luid, self.adapter_luid,
&self.mark_unsupported, &self.mark_unsupported,
); );
@ -2065,7 +2075,7 @@ pub enum MediaData {
VideoFrame(Box<VideoFrame>), VideoFrame(Box<VideoFrame>),
AudioFrame(Box<AudioFrame>), AudioFrame(Box<AudioFrame>),
AudioFormat(AudioFormat), AudioFormat(AudioFormat),
Reset(usize), Reset(Option<usize>),
RecordScreen(bool, usize, i32, i32, String), RecordScreen(bool, usize, i32, i32, String),
} }
@ -2241,8 +2251,16 @@ where
} }
} }
MediaData::Reset(display) => { MediaData::Reset(display) => {
if let Some(handler_controler) = handler_controller_map.get_mut(&display) { if let Some(display) = display {
handler_controler.handler.reset(None); 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) => { MediaData::RecordScreen(start, display, w, h, id) => {
@ -2945,6 +2963,7 @@ pub enum Data {
ElevateWithLogon(String, String), ElevateWithLogon(String, String),
NewVoiceCall, NewVoiceCall,
CloseVoiceCall, CloseVoiceCall,
ResetDecoder(Option<usize>),
} }
/// Keycode for key events. /// Keycode for key events.

View File

@ -843,6 +843,9 @@ impl<T: InvokeUiSession> Remote<T> {
.on_voice_call_closed("Closed manually by the peer"); .on_voice_call_closed("Closed manually by the peer");
allow_err!(peer.send(&msg).await); allow_err!(peer.send(&msg).await);
} }
Data::ResetDecoder(display) => {
self.video_sender.send(MediaData::Reset(display)).ok();
}
_ => {} _ => {}
} }
true true
@ -1371,7 +1374,7 @@ impl<T: InvokeUiSession> Remote<T> {
Some(misc::Union::SwitchDisplay(s)) => { Some(misc::Union::SwitchDisplay(s)) => {
self.handler.handle_peer_switch_display(&s); self.handler.handle_peer_switch_display(&s);
self.video_sender self.video_sender
.send(MediaData::Reset(s.display as _)) .send(MediaData::Reset(Some(s.display as _)))
.ok(); .ok();
if s.width > 0 && s.height > 0 { if s.width > 0 && s.height > 0 {
self.handler.set_display( self.handler.set_display(

View File

@ -158,13 +158,6 @@ pub type NotifyMessageBox = fn(String, String, String, String) -> dyn Future<Out
pub const CLIPBOARD_NAME: &'static str = "clipboard"; pub const CLIPBOARD_NAME: &'static str = "clipboard";
pub const CLIPBOARD_INTERVAL: u64 = 333; pub const CLIPBOARD_INTERVAL: u64 = 333;
#[cfg(all(target_os = "macos", feature = "flutter_texture_render"))]
// https://developer.apple.com/forums/thread/712709
// Memory alignment should be multiple of 64.
pub const DST_STRIDE_RGBA: usize = 64;
#[cfg(not(all(target_os = "macos", feature = "flutter_texture_render")))]
pub const DST_STRIDE_RGBA: usize = 1;
// the executable name of the portable version // the executable name of the portable version
pub const PORTABLE_APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME"; pub const PORTABLE_APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME";
@ -1622,6 +1615,24 @@ fn read_custom_client_advanced_settings(
} }
} }
#[inline]
#[cfg(target_os = "macos")]
pub fn get_dst_stride_rgba() -> 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) { pub fn read_custom_client(config: &str) {
let Ok(data) = decode64(config) else { let Ok(data) = decode64(config) else {
log::error!("Failed to decode custom client config"); log::error!("Failed to decode custom client config");

View File

@ -4,7 +4,7 @@ use crate::{
ui_session_interface::{io_loop, InvokeUiSession, Session}, ui_session_interface::{io_loop, InvokeUiSession, Session},
}; };
use flutter_rust_bridge::StreamSink; 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::{ use hbb_common::dlopen::{
symbor::{Library, Symbol}, symbor::{Library, Symbol},
Error as LibError, Error as LibError,
@ -16,15 +16,15 @@ use hbb_common::{
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
use std::os::raw::c_void;
use std::{ use std::{
collections::HashMap, collections::HashMap,
ffi::CString, ffi::CString,
os::raw::{c_char, c_int}, os::raw::{c_char, c_int, c_void},
str::FromStr, 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) /// 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<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
} }
#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))] #[cfg(target_os = "windows")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("texture_rgba_renderer_plugin.dll"); pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("texture_rgba_renderer_plugin.dll");
} }
#[cfg(all(target_os = "linux", feature = "flutter_texture_render"))] #[cfg(target_os = "linux")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("libtexture_rgba_renderer_plugin.so"); pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("libtexture_rgba_renderer_plugin.so");
} }
#[cfg(all(target_os = "macos", feature = "flutter_texture_render"))] #[cfg(target_os = "macos")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open_self(); pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open_self();
} }
#[cfg(all(target_os = "windows", feature = "vram"))] #[cfg(target_os = "windows")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref TEXTURE_GPU_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("flutter_gpu_texture_renderer_plugin.dll"); pub static ref TEXTURE_GPU_RENDERER_PLUGIN: Result<Library, LibError> = 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)] #[derive(Default)]
struct SessionHandler { struct SessionHandler {
event_stream: Option<StreamSink<EventToUI>>, event_stream: Option<StreamSink<EventToUI>>,
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
renderer: VideoRenderer, renderer: VideoRenderer,
} }
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum RenderType { enum RenderType {
PixelBuffer, PixelBuffer,
@ -180,22 +178,32 @@ enum RenderType {
Texture, Texture,
} }
#[derive(Default, Clone)] #[derive(Clone)]
pub struct FlutterHandler { pub struct FlutterHandler {
// ui session id -> display handler data // ui session id -> display handler data
session_handlers: Arc<RwLock<HashMap<SessionID, SessionHandler>>>, session_handlers: Arc<RwLock<HashMap<SessionID, SessionHandler>>>,
#[cfg(not(feature = "flutter_texture_render"))]
display_rgbas: Arc<RwLock<HashMap<usize, RgbaData>>>, display_rgbas: Arc<RwLock<HashMap<usize, RgbaData>>>,
peer_info: Arc<RwLock<PeerInfo>>, peer_info: Arc<RwLock<PeerInfo>>,
#[cfg(any(
not(feature = "flutter_texture_render"),
all(feature = "flutter_texture_render", feature = "plugin_framework")
))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
hooks: Arc<RwLock<HashMap<String, SessionHook>>>, hooks: Arc<RwLock<HashMap<String, SessionHook>>>,
use_texture_render: Arc<AtomicBool>,
}
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)] #[derive(Default, Clone)]
struct RgbaData { struct RgbaData {
// SAFETY: [rgba] is guarded by [rgba_valid], and it's safe to reach [rgba] with `rgba_valid == true`. // 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, valid: bool,
} }
#[cfg(feature = "flutter_texture_render")]
pub type FlutterRgbaRendererPluginOnRgba = unsafe extern "C" fn( pub type FlutterRgbaRendererPluginOnRgba = unsafe extern "C" fn(
texture_rgba: *mut c_void, texture_rgba: *mut c_void,
buffer: *const u8, buffer: *const u8,
@ -221,15 +228,11 @@ pub type FlutterGpuTextureRendererPluginCApiSetTexture =
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
pub type FlutterGpuTextureRendererPluginCApiGetAdapterLuid = unsafe extern "C" fn() -> i64; pub type FlutterGpuTextureRendererPluginCApiGetAdapterLuid = unsafe extern "C" fn() -> i64;
#[cfg(feature = "flutter_texture_render")]
pub(super) type TextureRgbaPtr = usize; pub(super) type TextureRgbaPtr = usize;
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
struct DisplaySessionInfo { struct DisplaySessionInfo {
// TextureRgba pointer in flutter native. // TextureRgba pointer in flutter native.
#[cfg(feature = "flutter_texture_render")]
texture_rgba_ptr: TextureRgbaPtr, texture_rgba_ptr: TextureRgbaPtr,
#[cfg(feature = "flutter_texture_render")]
size: (usize, usize), size: (usize, usize),
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
gpu_output_ptr: usize, gpu_output_ptr: usize,
@ -237,21 +240,19 @@ struct DisplaySessionInfo {
} }
// Video Texture Renderer in Flutter // Video Texture Renderer in Flutter
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
#[derive(Clone)] #[derive(Clone)]
struct VideoRenderer { struct VideoRenderer {
is_support_multi_ui_session: bool, is_support_multi_ui_session: bool,
map_display_sessions: Arc<RwLock<HashMap<usize, DisplaySessionInfo>>>, map_display_sessions: Arc<RwLock<HashMap<usize, DisplaySessionInfo>>>,
#[cfg(feature = "flutter_texture_render")] #[cfg(not(any(target_os = "android", target_os = "ios")))]
on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>, on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>,
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
on_texture_func: Option<Symbol<'static, FlutterGpuTextureRendererPluginCApiSetTexture>>, on_texture_func: Option<Symbol<'static, FlutterGpuTextureRendererPluginCApiSetTexture>>,
} }
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
impl Default for VideoRenderer { impl Default for VideoRenderer {
fn default() -> Self { 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 { let on_rgba_func = match &*TEXTURE_RGBA_RENDERER_PLUGIN {
Ok(lib) => { Ok(lib) => {
let find_sym_res = unsafe { let find_sym_res = unsafe {
@ -295,7 +296,7 @@ impl Default for VideoRenderer {
Self { Self {
map_display_sessions: Default::default(), map_display_sessions: Default::default(),
is_support_multi_ui_session: false, is_support_multi_ui_session: false,
#[cfg(feature = "flutter_texture_render")] #[cfg(not(any(target_os = "android", target_os = "ios")))]
on_rgba_func, on_rgba_func,
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
on_texture_func, on_texture_func,
@ -303,10 +304,8 @@ impl Default for VideoRenderer {
} }
} }
#[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
impl VideoRenderer { impl VideoRenderer {
#[inline] #[inline]
#[cfg(feature = "flutter_texture_render")]
fn set_size(&mut self, display: usize, width: usize, height: usize) { fn set_size(&mut self, display: usize, width: usize, height: usize) {
let mut sessions_lock = self.map_display_sessions.write().unwrap(); let mut sessions_lock = self.map_display_sessions.write().unwrap();
if let Some(info) = sessions_lock.get_mut(&display) { 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) { fn register_pixelbuffer_texture(&self, display: usize, ptr: usize) {
let mut sessions_lock = self.map_display_sessions.write().unwrap(); let mut sessions_lock = self.map_display_sessions.write().unwrap();
if ptr == 0 { if ptr == 0 {
@ -378,7 +376,6 @@ impl VideoRenderer {
if info.gpu_output_ptr != usize::default() { if info.gpu_output_ptr != usize::default() {
info.gpu_output_ptr = usize::default(); info.gpu_output_ptr = usize::default();
} }
#[cfg(feature = "flutter_texture_render")]
if info.texture_rgba_ptr != usize::default() { if info.texture_rgba_ptr != usize::default() {
return; return;
} }
@ -400,9 +397,7 @@ impl VideoRenderer {
sessions_lock.insert( sessions_lock.insert(
display, display,
DisplaySessionInfo { DisplaySessionInfo {
#[cfg(feature = "flutter_texture_render")]
texture_rgba_ptr: usize::default(), texture_rgba_ptr: usize::default(),
#[cfg(feature = "flutter_texture_render")]
size: (0, 0), size: (0, 0),
gpu_output_ptr: ptr, gpu_output_ptr: ptr,
notify_render_type: None, 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 { pub fn on_rgba(&self, display: usize, rgba: &scrap::ImageRgb) -> bool {
let mut write_lock = self.map_display_sessions.write().unwrap(); let mut write_lock = self.map_display_sessions.write().unwrap();
let opt_info = if !self.is_support_multi_ui_session { let opt_info = if !self.is_support_multi_ui_session {
@ -498,10 +493,7 @@ impl VideoRenderer {
impl SessionHandler { impl SessionHandler {
pub fn on_waiting_for_image_dialog_show(&self) { 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 // rgba array render will notify every frame
} }
} }
@ -583,6 +575,11 @@ impl FlutterHandler {
let _ = hooks.remove(key); let _ = hooks.remove(key);
true 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 { impl InvokeUiSession for FlutterHandler {
@ -769,60 +766,27 @@ impl InvokeUiSession for FlutterHandler {
fn adapt_size(&self) {} fn adapt_size(&self) {}
#[inline] #[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) { fn on_rgba(&self, display: usize, rgba: &mut scrap::ImageRgb) {
// Give a chance for plugins or etc to hook a rgba data. if self.use_texture_render.load(Ordering::Relaxed) {
#[cfg(not(any(target_os = "android", target_os = "ios")))] self.on_rgba_flutter_texture_render(display, rgba);
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::<Vec<u8>>(&mut rgba.raw, &mut rgba_data.data);
} else { } else {
let mut rgba_data = RgbaData::default(); self.on_rgba_soft_render(display, rgba);
std::mem::swap::<Vec<u8>>(&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] #[inline]
#[cfg(feature = "flutter_texture_render")] #[cfg(any(target_os = "android", target_os = "ios"))]
fn on_rgba(&self, display: usize, rgba: &mut scrap::ImageRgb) { fn on_rgba(&self, display: usize, rgba: &mut scrap::ImageRgb) {
for (_, session) in self.session_handlers.read().unwrap().iter() { self.on_rgba_soft_render(display, rgba);
if session.renderer.on_rgba(display, rgba) {
if let Some(stream) = &session.event_stream {
stream.add(EventToUI::Rgba(display));
}
}
}
} }
#[inline] #[inline]
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
fn on_texture(&self, display: usize, texture: *mut c_void) { 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() { for (_, session) in self.session_handlers.read().unwrap().iter() {
if session.renderer.on_texture(display, texture) { if session.renderer.on_texture(display, texture) {
if let Some(stream) = &session.event_stream { 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 features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
let resolutions = serialize_resolutions(&pi.resolutions.resolutions); let resolutions = serialize_resolutions(&pi.resolutions.resolutions);
*self.peer_info.write().unwrap() = pi.clone(); *self.peer_info.write().unwrap() = pi.clone();
#[cfg(feature = "flutter_texture_render")] #[cfg(not(any(target_os = "android", target_os = "ios")))]
{ let is_support_multi_ui_session = crate::common::is_support_multi_ui_session(&pi.version);
self.session_handlers #[cfg(any(target_os = "android", target_os = "ios"))]
.write() let is_support_multi_ui_session = false;
.unwrap() self.session_handlers
.values_mut() .write()
.for_each(|h| { .unwrap()
h.renderer.is_support_multi_ui_session = .values_mut()
crate::common::is_support_multi_ui_session(&pi.version); .for_each(|h| {
}); h.renderer.is_support_multi_ui_session = is_support_multi_ui_session;
} });
self.push_event( self.push_event(
"peer_info", "peer_info",
&[ &[
@ -1028,7 +992,6 @@ impl InvokeUiSession for FlutterHandler {
#[inline] #[inline]
fn get_rgba(&self, _display: usize) -> *const u8 { 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 let Some(rgba_data) = self.display_rgbas.read().unwrap().get(&_display) {
if rgba_data.valid { if rgba_data.valid {
return rgba_data.data.as_ptr(); return rgba_data.data.as_ptr();
@ -1039,13 +1002,65 @@ impl InvokeUiSession for FlutterHandler {
#[inline] #[inline]
fn next_rgba(&self, _display: usize) { 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) { if let Some(rgba_data) = self.display_rgbas.write().unwrap().get_mut(&_display) {
rgba_data.valid = false; 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::<Vec<u8>>(&mut rgba.raw, &mut rgba_data.data);
} else {
let mut rgba_data = RgbaData::default();
std::mem::swap::<Vec<u8>>(&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. // This function is only used for the default connection session.
pub fn session_add_existed(peer_id: String, session_id: SessionID) -> ResultType<()> { pub fn session_add_existed(peer_id: String, session_id: SessionID) -> ResultType<()> {
sessions::insert_peer_session_id(peer_id, ConnType::DEFAULT_CONN, session_id); 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()) 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( session.lc.write().unwrap().initialize(
id.to_owned(), id.to_owned(),
conn_type, conn_type,
switch_uuid, switch_uuid,
force_relay, force_relay,
adapter_luid, get_adapter_luid(),
shared_password, shared_password,
); );
@ -1172,14 +1182,11 @@ pub fn session_start_(
if let Some(session) = sessions::get_session_by_session_id(session_id) { if let Some(session) = sessions::get_session_by_session_id(session_id) {
let is_first_ui_session = session.session_handlers.read().unwrap().len() == 1; let is_first_ui_session = session.session_handlers.read().unwrap().len() == 1;
if !is_connected && is_first_ui_session { if !is_connected && is_first_ui_session {
#[cfg(feature = "flutter_texture_render")]
log::info!( log::info!(
"Session {} start, render by flutter texture rgba plugin", "Session {} start, use texture render: {}",
id 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(); let session = (*session).clone();
std::thread::spawn(move || { std::thread::spawn(move || {
let round = session.connection_round_state.lock().unwrap().new_round(); let round = session.connection_round_state.lock().unwrap().new_round();
@ -1437,14 +1444,13 @@ fn char_to_session_id(c: *const char) -> ResultType<SessionID> {
SessionID::from_str(str).map_err(|e| anyhow!("{:?}", e)) SessionID::from_str(str).map_err(|e| anyhow!("{:?}", e))
} }
pub fn session_get_rgba_size(_session_id: SessionID, _display: usize) -> usize { 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) {
if let Some(session) = sessions::get_session_by_session_id(&_session_id) {
return session return session
.display_rgbas .display_rgbas
.read() .read()
.unwrap() .unwrap()
.get(&_display) .get(&display)
.map_or(0, |rgba| rgba.data.len()); .map_or(0, |rgba| rgba.data.len());
} }
0 0
@ -1468,34 +1474,32 @@ pub fn session_next_rgba(session_id: SessionID, display: usize) {
} }
#[inline] #[inline]
pub fn session_set_size(_session_id: SessionID, _display: usize, _width: usize, _height: usize) { pub fn session_set_size(session_id: SessionID, display: usize, width: usize, height: usize) {
#[cfg(feature = "flutter_texture_render")]
for s in sessions::get_sessions() { for s in sessions::get_sessions() {
if let Some(h) = s if let Some(h) = s
.ui_handler .ui_handler
.session_handlers .session_handlers
.write() .write()
.unwrap() .unwrap()
.get_mut(&_session_id) .get_mut(&session_id)
{ {
h.renderer.set_size(_display, _width, _height); h.renderer.set_size(display, width, height);
break; break;
} }
} }
} }
#[inline] #[inline]
pub fn session_register_pixelbuffer_texture(_session_id: SessionID, _display: usize, _ptr: usize) { pub fn session_register_pixelbuffer_texture(session_id: SessionID, display: usize, ptr: usize) {
#[cfg(feature = "flutter_texture_render")]
for s in sessions::get_sessions() { for s in sessions::get_sessions() {
if let Some(h) = s if let Some(h) = s
.ui_handler .ui_handler
.session_handlers .session_handlers
.read() .read()
.unwrap() .unwrap()
.get(&_session_id) .get(&session_id)
{ {
h.renderer.register_pixelbuffer_texture(_display, _ptr); h.renderer.register_pixelbuffer_texture(display, ptr);
break; 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<i64> {
None
}
#[cfg(feature = "vram")] #[cfg(feature = "vram")]
pub fn get_adapter_luid() -> Option<i64> { pub fn get_adapter_luid() -> Option<i64> {
if !crate::ui_interface::use_texture_render() {
return None;
}
let get_adapter_luid_func = match &*TEXTURE_GPU_RENDERER_PLUGIN { let get_adapter_luid_func = match &*TEXTURE_GPU_RENDERER_PLUGIN {
Ok(lib) => { Ok(lib) => {
let find_sym_res = unsafe { 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. // sessions mod is used to avoid the big lock of sessions' map.
pub mod sessions { pub mod sessions {
#[cfg(feature = "flutter_texture_render")]
use std::collections::HashSet; use std::collections::HashSet;
use super::*; use super::*;
@ -1781,14 +1793,6 @@ pub mod sessions {
for (peer_key, s) in SESSIONS.write().unwrap().iter_mut() { for (peer_key, s) in SESSIONS.write().unwrap().iter_mut() {
let mut write_lock = s.ui_handler.session_handlers.write().unwrap(); let mut write_lock = s.ui_handler.session_handlers.write().unwrap();
let remove_ret = write_lock.remove(id); 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 { match remove_ret {
Some(_) => { Some(_) => {
if write_lock.is_empty() { if write_lock.is_empty() {
@ -1804,7 +1808,6 @@ pub mod sessions {
SESSIONS.write().unwrap().remove(&remove_peer_key?) SESSIONS.write().unwrap().remove(&remove_peer_key?)
} }
#[cfg(feature = "flutter_texture_render")]
fn check_remove_unused_displays( fn check_remove_unused_displays(
current: Option<usize>, current: Option<usize>,
session_id: &SessionID, session_id: &SessionID,
@ -1852,7 +1855,6 @@ pub mod sessions {
s.capture_displays(vec![], vec![], value); s.capture_displays(vec![], vec![], value);
} else { } else {
// Check if other displays are needed. // Check if other displays are needed.
#[cfg(feature = "flutter_texture_render")]
if value.len() == 1 { if value.len() == 1 {
check_remove_unused_displays( check_remove_unused_displays(
Some(value[0] as _), Some(value[0] as _),
@ -1892,16 +1894,14 @@ pub mod sessions {
session_id: SessionID, session_id: SessionID,
) -> bool { ) -> bool {
if let Some(s) = SESSIONS.read().unwrap().get(&(peer_id, conn_type)) { 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(); let mut h = SessionHandler::default();
#[cfg(feature = "flutter_texture_render")] #[cfg(not(any(target_os = "android", target_os = "ios")))]
{ let is_support_multi_ui_session = crate::common::is_support_multi_ui_session(
h.renderer.is_support_multi_ui_session = crate::common::is_support_multi_ui_session( &s.ui_handler.peer_info.read().unwrap().version,
&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 let _ = s
.ui_handler .ui_handler
.session_handlers .session_handlers

View File

@ -2,7 +2,7 @@ use crate::{
client::file_trait::FileManager, client::file_trait::FileManager,
common::{is_keyboard_mode_supported, make_fd_to_json}, common::{is_keyboard_mode_supported, make_fd_to_json},
flutter::{ 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::*, input::*,
ui_interface::{self, *}, 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) { 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)
super::flutter::session_set_size(_session_id, _display, _width, _height)
} }
pub fn session_send_selected_session_id(session_id: SessionID, sid: String) { pub fn session_send_selected_session_id(session_id: SessionID, sid: String) {
@ -774,13 +773,13 @@ pub fn main_show_option(_key: String) -> SyncReturn<bool> {
pub fn main_set_option(key: String, value: String) { pub fn main_set_option(key: String, value: String) {
if key.eq("custom-rendezvous-server") { if key.eq("custom-rendezvous-server") {
set_option(key, value); set_option(key, value.clone());
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
crate::rendezvous_mediator::RendezvousMediator::restart(); crate::rendezvous_mediator::RendezvousMediator::restart();
#[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))]
crate::common::test_rendezvous_server(); crate::common::test_rendezvous_server();
} else { } else {
set_option(key, value); set_option(key, value.clone());
} }
} }
@ -892,12 +891,25 @@ pub fn main_get_local_option(key: String) -> SyncReturn<String> {
SyncReturn(get_local_option(key)) SyncReturn(get_local_option(key))
} }
pub fn main_get_use_texture_render() -> SyncReturn<bool> {
SyncReturn(use_texture_render())
}
pub fn main_get_env(key: String) -> SyncReturn<String> { pub fn main_get_env(key: String) -> SyncReturn<String> {
SyncReturn(std::env::var(key).unwrap_or_default()) SyncReturn(std::env::var(key).unwrap_or_default())
} }
pub fn main_set_local_option(key: String, value: String) { 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`. // We do use use `main_get_local_option` and `main_set_local_option`.
@ -1824,10 +1836,6 @@ pub fn main_hide_docker() -> SyncReturn<bool> {
SyncReturn(true) SyncReturn(true)
} }
pub fn main_has_pixelbuffer_texture_render() -> SyncReturn<bool> {
SyncReturn(cfg!(feature = "flutter_texture_render"))
}
pub fn main_has_file_clipboard() -> SyncReturn<bool> { pub fn main_has_file_clipboard() -> SyncReturn<bool> {
let ret = cfg!(any( let ret = cfg!(any(
target_os = "windows", target_os = "windows",

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", "清除 Wayland 的屏幕选择后,您可以重新选择分享的屏幕。"), ("clear_Wayland_screen_selection_tip", "清除 Wayland 的屏幕选择后,您可以重新选择分享的屏幕。"),
("confirm_clear_Wayland_screen_selection_tip", "是否确认清除 Wayland 的分享屏幕选择?"), ("confirm_clear_Wayland_screen_selection_tip", "是否确认清除 Wayland 的分享屏幕选择?"),
("android_new_voice_call_tip", "收到新的语音呼叫请求。如果您接受,音频将切换为语音通信。"), ("android_new_voice_call_tip", "收到新的语音呼叫请求。如果您接受,音频将切换为语音通信。"),
("texture_render_tip", "使用纹理渲染,使图片更加流畅。"),
("Use texture rendering", "使用纹理渲染"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", "پس از پاک کردن صفحه انتخابی، می توانید صفحه را برای اشتراک گذاری مجدد انتخاب کنید"), ("clear_Wayland_screen_selection_tip", "پس از پاک کردن صفحه انتخابی، می توانید صفحه را برای اشتراک گذاری مجدد انتخاب کنید"),
("confirm_clear_Wayland_screen_selection_tip", "را پاک می کنید؟ Wayland آیا مطمئن هستید که انتخاب صفحه"), ("confirm_clear_Wayland_screen_selection_tip", "را پاک می کنید؟ Wayland آیا مطمئن هستید که انتخاب صفحه"),
("android_new_voice_call_tip", "یک درخواست تماس صوتی جدید دریافت شد. اگر بپذیرید، صدا به ارتباط صوتی تغییر خواهد کرد."), ("android_new_voice_call_tip", "یک درخواست تماس صوتی جدید دریافت شد. اگر بپذیرید، صدا به ارتباط صوتی تغییر خواهد کرد."),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("confirm_clear_Wayland_screen_selection_tip", "Vai tiešām notīrīt Wayland ekrāna atlasi?"),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", "После отмены можно заново выбрать экран для демонстрации."), ("clear_Wayland_screen_selection_tip", "После отмены можно заново выбрать экран для демонстрации."),
("confirm_clear_Wayland_screen_selection_tip", "Отменить выбор экрана Wayland?"), ("confirm_clear_Wayland_screen_selection_tip", "Отменить выбор экрана Wayland?"),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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ť."), ("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?"), ("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."), ("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(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", "清除 Wayland 的螢幕選擇後,您可以重新選擇分享的螢幕。"), ("clear_Wayland_screen_selection_tip", "清除 Wayland 的螢幕選擇後,您可以重新選擇分享的螢幕。"),
("confirm_clear_Wayland_screen_selection_tip", "是否確認清除 Wayland 的分享螢幕選擇?"), ("confirm_clear_Wayland_screen_selection_tip", "是否確認清除 Wayland 的分享螢幕選擇?"),
("android_new_voice_call_tip", "收到新的語音通話請求。如果您接受,音訊將切換為語音通訊。"), ("android_new_voice_call_tip", "收到新的語音通話請求。如果您接受,音訊將切換為語音通訊。"),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", "Після очищення вибору екрана ви можете повторно вибрати екран для поширення."), ("clear_Wayland_screen_selection_tip", "Після очищення вибору екрана ви можете повторно вибрати екран для поширення."),
("confirm_clear_Wayland_screen_selection_tip", "Ви впевнені, що хочете очистити вибір екрана Wayland?"), ("confirm_clear_Wayland_screen_selection_tip", "Ви впевнені, що хочете очистити вибір екрана Wayland?"),
("android_new_voice_call_tip", "Отримано новий запит на голосовий дзвінок. Якщо ви приймете його, аудіо перемкнеться на голосовий звʼязок."), ("android_new_voice_call_tip", "Отримано новий запит на голосовий дзвінок. Якщо ви приймете його, аудіо перемкнеться на голосовий звʼязок."),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -613,5 +613,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("clear_Wayland_screen_selection_tip", ""), ("clear_Wayland_screen_selection_tip", ""),
("confirm_clear_Wayland_screen_selection_tip", ""), ("confirm_clear_Wayland_screen_selection_tip", ""),
("android_new_voice_call_tip", ""), ("android_new_voice_call_tip", ""),
("texture_render_tip", ""),
("Use texture rendering", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -53,7 +53,7 @@ use scrap::{
codec::{Encoder, EncoderCfg, Quality}, codec::{Encoder, EncoderCfg, Quality},
record::{Recorder, RecorderContext}, record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecFormat, Display, EncodeInput, Frame, TraitCapturer, CodecFormat, Display, EncodeInput, TraitCapturer,
}; };
#[cfg(windows)] #[cfg(windows)]
use std::sync::Once; use std::sync::Once;

View File

@ -169,6 +169,26 @@ pub fn get_option<T: AsRef<str>>(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] #[inline]
pub fn get_local_option(key: String) -> String { pub fn get_local_option(key: String) -> String {
LocalConfig::get_option(&key) LocalConfig::get_option(&key)
@ -898,7 +918,8 @@ pub fn has_vram() -> bool {
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
#[inline] #[inline]
pub fn supported_hwdecodings() -> (bool, bool) { 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)] #[allow(unused_mut)]
let (mut h264, mut h265) = (decoding.ability_h264 > 0, decoding.ability_h265 > 0); let (mut h264, mut h265) = (decoding.ability_h264 > 0, decoding.ability_h265 > 0);
#[cfg(feature = "vram")] #[cfg(feature = "vram")]

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
common::{get_supported_keyboard_modes, is_keyboard_mode_supported}, common::{get_supported_keyboard_modes, is_keyboard_mode_supported},
input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL}, input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL},
ui_interface::use_texture_render,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
@ -448,7 +449,7 @@ impl<T: InvokeUiSession> Session<T> {
let mark_unsupported = self.lc.read().unwrap().mark_unsupported.clone(); let mark_unsupported = self.lc.read().unwrap().mark_unsupported.clone();
let decoder = scrap::codec::Decoder::supported_decodings( let decoder = scrap::codec::Decoder::supported_decodings(
None, None,
cfg!(feature = "flutter"), use_texture_render(),
luid, luid,
&mark_unsupported, &mark_unsupported,
); );
@ -469,6 +470,11 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::Message(msg)); 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) { pub fn restart_remote_device(&self) {
let mut lc = self.lc.write().unwrap(); let mut lc = self.lc.write().unwrap();
lc.restarting_remote_device = true; lc.restarting_remote_device = true;
@ -732,8 +738,7 @@ impl<T: InvokeUiSession> Session<T> {
msg_out.set_misc(misc); msg_out.set_misc(misc);
self.send(Data::Message(msg_out)); self.send(Data::Message(msg_out));
#[cfg(not(feature = "flutter_texture_render"))] if !use_texture_render() {
{
self.capture_displays(vec![], vec![], vec![display]); self.capture_displays(vec![], vec![], vec![display]);
} }
} }