Initial commit: RustDesk 1.4.7 macOS desktop port
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common) - Patched Flutter 3.44 / Dart 3.12 compatibility: * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64 * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0 * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64 - Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter - Verified flutter build macos --debug and --release both produce working .app - Verified .dmg installer (27MB arm64) created via hdiutil - Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart';
|
||||
import 'package:flutter_hbb/common/shared_state.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/models/model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import './platform_model.dart';
|
||||
|
||||
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'
|
||||
if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart';
|
||||
|
||||
class _PixelbufferTexture {
|
||||
int _textureKey = -1;
|
||||
int _display = 0;
|
||||
SessionID? _sessionId;
|
||||
bool _destroying = false;
|
||||
int? _id;
|
||||
|
||||
final textureRenderer = TextureRgbaRenderer();
|
||||
|
||||
int get display => _display;
|
||||
|
||||
create(int d, SessionID sessionId, FFI ffi) {
|
||||
_display = d;
|
||||
_textureKey = bind.getNextTextureKey();
|
||||
_sessionId = sessionId;
|
||||
|
||||
textureRenderer.createTexture(_textureKey).then((id) async {
|
||||
_id = id;
|
||||
if (id != -1) {
|
||||
ffi.textureModel.setRgbaTextureId(display: d, id: id);
|
||||
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
||||
platformFFI.registerPixelbufferTexture(sessionId, display, ptr);
|
||||
debugPrint(
|
||||
"create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
destroy(bool unregisterTexture, FFI ffi) async {
|
||||
if (!_destroying && _textureKey != -1 && _sessionId != null) {
|
||||
_destroying = true;
|
||||
if (unregisterTexture) {
|
||||
platformFFI.registerPixelbufferTexture(_sessionId!, display, 0);
|
||||
// sleep for a while to avoid the texture is used after it's unregistered.
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
}
|
||||
await textureRenderer.closeTexture(_textureKey);
|
||||
_textureKey = -1;
|
||||
_destroying = false;
|
||||
debugPrint(
|
||||
"destroy pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _GpuTexture {
|
||||
int _textureId = -1;
|
||||
SessionID? _sessionId;
|
||||
final support = bind.mainHasGpuTextureRender();
|
||||
bool _destroying = false;
|
||||
int _display = 0;
|
||||
int? _id;
|
||||
int? _output;
|
||||
|
||||
int get display => _display;
|
||||
|
||||
final gpuTextureRenderer = FlutterGpuTextureRenderer();
|
||||
|
||||
_GpuTexture();
|
||||
|
||||
create(int d, SessionID sessionId, FFI ffi) {
|
||||
if (support) {
|
||||
_sessionId = sessionId;
|
||||
_display = d;
|
||||
|
||||
gpuTextureRenderer.registerTexture().then((id) async {
|
||||
_id = id;
|
||||
if (id != null) {
|
||||
_textureId = id;
|
||||
ffi.textureModel.setGpuTextureId(display: d, id: id);
|
||||
final output = await gpuTextureRenderer.output(id);
|
||||
_output = output;
|
||||
if (output != null) {
|
||||
platformFFI.registerGpuTexture(sessionId, d, output);
|
||||
}
|
||||
debugPrint(
|
||||
"create gpu texture: peerId: ${ffi.id} display:$_display, textureId:$id, output:$output");
|
||||
}
|
||||
}, onError: (err) {
|
||||
debugPrint("Failed to register gpu texture:$err");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
destroy(bool unregisterTexture, FFI ffi) async {
|
||||
// must stop texture render, render unregistered texture cause crash
|
||||
if (!_destroying && support && _sessionId != null && _textureId != -1) {
|
||||
_destroying = true;
|
||||
if (unregisterTexture) {
|
||||
platformFFI.registerGpuTexture(_sessionId!, _display, 0);
|
||||
// sleep for a while to avoid the texture is used after it's unregistered.
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
}
|
||||
await gpuTextureRenderer.unregisterTexture(_textureId);
|
||||
_textureId = -1;
|
||||
_destroying = false;
|
||||
debugPrint(
|
||||
"destroy gpu texture: peerId: ${ffi.id} display:$_display, textureId:$_id, output:$_output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _Control {
|
||||
RxInt textureID = (-1).obs;
|
||||
|
||||
int _rgbaTextureId = -1;
|
||||
int get rgbaTextureId => _rgbaTextureId;
|
||||
int _gpuTextureId = -1;
|
||||
int get gpuTextureId => _gpuTextureId;
|
||||
bool _isGpuTexture = false;
|
||||
bool get isGpuTexture => _isGpuTexture;
|
||||
|
||||
setTextureType({bool gpuTexture = false}) {
|
||||
_isGpuTexture = gpuTexture;
|
||||
textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
|
||||
}
|
||||
|
||||
setRgbaTextureId(int id) {
|
||||
_rgbaTextureId = id;
|
||||
textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
|
||||
}
|
||||
|
||||
setGpuTextureId(int id) {
|
||||
_gpuTextureId = id;
|
||||
textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
|
||||
}
|
||||
}
|
||||
|
||||
class TextureModel {
|
||||
final WeakReference<FFI> parent;
|
||||
final Map<int, _Control> _control = {};
|
||||
final Map<int, _PixelbufferTexture> _pixelbufferRenderTextures = {};
|
||||
final Map<int, _GpuTexture> _gpuRenderTextures = {};
|
||||
|
||||
TextureModel(this.parent);
|
||||
|
||||
setTextureType({required int display, required bool gpuTexture}) {
|
||||
debugPrint("setTextureType: display=$display, isGpuTexture=$gpuTexture");
|
||||
ensureControl(display);
|
||||
_control[display]?.setTextureType(gpuTexture: gpuTexture);
|
||||
// For versions that do not support multiple displays, the display parameter is always 0, need set type of current display
|
||||
final ffi = parent.target;
|
||||
if (ffi == null) return;
|
||||
if (!ffi.ffiModel.pi.isSupportMultiDisplay) {
|
||||
final currentDisplay = CurrentDisplayState.find(ffi.id).value;
|
||||
if (currentDisplay != display) {
|
||||
debugPrint(
|
||||
"setTextureType: currentDisplay=$currentDisplay, isGpuTexture=$gpuTexture");
|
||||
ensureControl(currentDisplay);
|
||||
_control[currentDisplay]?.setTextureType(gpuTexture: gpuTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setRgbaTextureId({required int display, required int id}) {
|
||||
ensureControl(display);
|
||||
_control[display]?.setRgbaTextureId(id);
|
||||
}
|
||||
|
||||
setGpuTextureId({required int display, required int id}) {
|
||||
ensureControl(display);
|
||||
_control[display]?.setGpuTextureId(id);
|
||||
}
|
||||
|
||||
RxInt getTextureId(int display) {
|
||||
ensureControl(display);
|
||||
return _control[display]!.textureID;
|
||||
}
|
||||
|
||||
updateCurrentDisplay(int curDisplay) {
|
||||
if (isWeb) return;
|
||||
final ffi = parent.target;
|
||||
if (ffi == null) return;
|
||||
tryCreateTexture(int idx) {
|
||||
if (!_pixelbufferRenderTextures.containsKey(idx)) {
|
||||
final renderTexture = _PixelbufferTexture();
|
||||
_pixelbufferRenderTextures[idx] = renderTexture;
|
||||
renderTexture.create(idx, ffi.sessionId, ffi);
|
||||
}
|
||||
if (!_gpuRenderTextures.containsKey(idx)) {
|
||||
final renderTexture = _GpuTexture();
|
||||
_gpuRenderTextures[idx] = renderTexture;
|
||||
renderTexture.create(idx, ffi.sessionId, ffi);
|
||||
}
|
||||
}
|
||||
|
||||
tryRemoveTexture(int idx) {
|
||||
_control.remove(idx);
|
||||
if (_pixelbufferRenderTextures.containsKey(idx)) {
|
||||
_pixelbufferRenderTextures[idx]!.destroy(true, ffi);
|
||||
_pixelbufferRenderTextures.remove(idx);
|
||||
}
|
||||
if (_gpuRenderTextures.containsKey(idx)) {
|
||||
_gpuRenderTextures[idx]!.destroy(true, ffi);
|
||||
_gpuRenderTextures.remove(idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (curDisplay == kAllDisplayValue) {
|
||||
final displays = ffi.ffiModel.pi.getCurDisplays();
|
||||
for (var i = 0; i < displays.length; i++) {
|
||||
tryCreateTexture(i);
|
||||
}
|
||||
} else {
|
||||
tryCreateTexture(curDisplay);
|
||||
for (var i = 0; i < ffi.ffiModel.pi.displays.length; i++) {
|
||||
if (i != curDisplay) {
|
||||
tryRemoveTexture(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRemotePageDispose(bool closeSession) async {
|
||||
final ffi = parent.target;
|
||||
if (ffi == null) return;
|
||||
for (final texture in _pixelbufferRenderTextures.values) {
|
||||
await texture.destroy(closeSession, ffi);
|
||||
}
|
||||
for (final texture in _gpuRenderTextures.values) {
|
||||
await texture.destroy(closeSession, ffi);
|
||||
}
|
||||
}
|
||||
|
||||
onViewCameraPageDispose(bool closeSession) async {
|
||||
final ffi = parent.target;
|
||||
if (ffi == null) return;
|
||||
for (final texture in _pixelbufferRenderTextures.values) {
|
||||
await texture.destroy(closeSession, ffi);
|
||||
}
|
||||
for (final texture in _gpuRenderTextures.values) {
|
||||
await texture.destroy(closeSession, ffi);
|
||||
}
|
||||
}
|
||||
|
||||
ensureControl(int display) {
|
||||
var ctl = _control[display];
|
||||
if (ctl == null) {
|
||||
ctl = _Control();
|
||||
_control[display] = ctl;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user