desktop_render_texture.dart 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart';
  3. import 'package:flutter_hbb/common/shared_state.dart';
  4. import 'package:flutter_hbb/consts.dart';
  5. import 'package:flutter_hbb/models/model.dart';
  6. import 'package:get/get.dart';
  7. import '../../common.dart';
  8. import './platform_model.dart';
  9. import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'
  10. if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart';
  11. class _PixelbufferTexture {
  12. int _textureKey = -1;
  13. int _display = 0;
  14. SessionID? _sessionId;
  15. bool _destroying = false;
  16. int? _id;
  17. final textureRenderer = TextureRgbaRenderer();
  18. int get display => _display;
  19. create(int d, SessionID sessionId, FFI ffi) {
  20. _display = d;
  21. _textureKey = bind.getNextTextureKey();
  22. _sessionId = sessionId;
  23. textureRenderer.createTexture(_textureKey).then((id) async {
  24. _id = id;
  25. if (id != -1) {
  26. ffi.textureModel.setRgbaTextureId(display: d, id: id);
  27. final ptr = await textureRenderer.getTexturePtr(_textureKey);
  28. platformFFI.registerPixelbufferTexture(sessionId, display, ptr);
  29. debugPrint(
  30. "create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id, texturePtr:$ptr");
  31. }
  32. });
  33. }
  34. destroy(bool unregisterTexture, FFI ffi) async {
  35. if (!_destroying && _textureKey != -1 && _sessionId != null) {
  36. _destroying = true;
  37. if (unregisterTexture) {
  38. platformFFI.registerPixelbufferTexture(_sessionId!, display, 0);
  39. // sleep for a while to avoid the texture is used after it's unregistered.
  40. await Future.delayed(Duration(milliseconds: 100));
  41. }
  42. await textureRenderer.closeTexture(_textureKey);
  43. _textureKey = -1;
  44. _destroying = false;
  45. debugPrint(
  46. "destroy pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$_id");
  47. }
  48. }
  49. }
  50. class _GpuTexture {
  51. int _textureId = -1;
  52. SessionID? _sessionId;
  53. final support = bind.mainHasGpuTextureRender();
  54. bool _destroying = false;
  55. int _display = 0;
  56. int? _id;
  57. int? _output;
  58. int get display => _display;
  59. final gpuTextureRenderer = FlutterGpuTextureRenderer();
  60. _GpuTexture();
  61. create(int d, SessionID sessionId, FFI ffi) {
  62. if (support) {
  63. _sessionId = sessionId;
  64. _display = d;
  65. gpuTextureRenderer.registerTexture().then((id) async {
  66. _id = id;
  67. if (id != null) {
  68. _textureId = id;
  69. ffi.textureModel.setGpuTextureId(display: d, id: id);
  70. final output = await gpuTextureRenderer.output(id);
  71. _output = output;
  72. if (output != null) {
  73. platformFFI.registerGpuTexture(sessionId, d, output);
  74. }
  75. debugPrint(
  76. "create gpu texture: peerId: ${ffi.id} display:$_display, textureId:$id, output:$output");
  77. }
  78. }, onError: (err) {
  79. debugPrint("Failed to register gpu texture:$err");
  80. });
  81. }
  82. }
  83. destroy(bool unregisterTexture, FFI ffi) async {
  84. // must stop texture render, render unregistered texture cause crash
  85. if (!_destroying && support && _sessionId != null && _textureId != -1) {
  86. _destroying = true;
  87. if (unregisterTexture) {
  88. platformFFI.registerGpuTexture(_sessionId!, _display, 0);
  89. // sleep for a while to avoid the texture is used after it's unregistered.
  90. await Future.delayed(Duration(milliseconds: 100));
  91. }
  92. await gpuTextureRenderer.unregisterTexture(_textureId);
  93. _textureId = -1;
  94. _destroying = false;
  95. debugPrint(
  96. "destroy gpu texture: peerId: ${ffi.id} display:$_display, textureId:$_id, output:$_output");
  97. }
  98. }
  99. }
  100. class _Control {
  101. RxInt textureID = (-1).obs;
  102. int _rgbaTextureId = -1;
  103. int get rgbaTextureId => _rgbaTextureId;
  104. int _gpuTextureId = -1;
  105. int get gpuTextureId => _gpuTextureId;
  106. bool _isGpuTexture = false;
  107. bool get isGpuTexture => _isGpuTexture;
  108. setTextureType({bool gpuTexture = false}) {
  109. _isGpuTexture = gpuTexture;
  110. textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
  111. }
  112. setRgbaTextureId(int id) {
  113. _rgbaTextureId = id;
  114. textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
  115. }
  116. setGpuTextureId(int id) {
  117. _gpuTextureId = id;
  118. textureID.value = _isGpuTexture ? gpuTextureId : rgbaTextureId;
  119. }
  120. }
  121. class TextureModel {
  122. final WeakReference<FFI> parent;
  123. final Map<int, _Control> _control = {};
  124. final Map<int, _PixelbufferTexture> _pixelbufferRenderTextures = {};
  125. final Map<int, _GpuTexture> _gpuRenderTextures = {};
  126. TextureModel(this.parent);
  127. setTextureType({required int display, required bool gpuTexture}) {
  128. debugPrint("setTextureType: display=$display, isGpuTexture=$gpuTexture");
  129. ensureControl(display);
  130. _control[display]?.setTextureType(gpuTexture: gpuTexture);
  131. // For versions that do not support multiple displays, the display parameter is always 0, need set type of current display
  132. final ffi = parent.target;
  133. if (ffi == null) return;
  134. if (!ffi.ffiModel.pi.isSupportMultiDisplay) {
  135. final currentDisplay = CurrentDisplayState.find(ffi.id).value;
  136. if (currentDisplay != display) {
  137. debugPrint(
  138. "setTextureType: currentDisplay=$currentDisplay, isGpuTexture=$gpuTexture");
  139. ensureControl(currentDisplay);
  140. _control[currentDisplay]?.setTextureType(gpuTexture: gpuTexture);
  141. }
  142. }
  143. }
  144. setRgbaTextureId({required int display, required int id}) {
  145. ensureControl(display);
  146. _control[display]?.setRgbaTextureId(id);
  147. }
  148. setGpuTextureId({required int display, required int id}) {
  149. ensureControl(display);
  150. _control[display]?.setGpuTextureId(id);
  151. }
  152. RxInt getTextureId(int display) {
  153. ensureControl(display);
  154. return _control[display]!.textureID;
  155. }
  156. updateCurrentDisplay(int curDisplay) {
  157. if (isWeb) return;
  158. final ffi = parent.target;
  159. if (ffi == null) return;
  160. tryCreateTexture(int idx) {
  161. if (!_pixelbufferRenderTextures.containsKey(idx)) {
  162. final renderTexture = _PixelbufferTexture();
  163. _pixelbufferRenderTextures[idx] = renderTexture;
  164. renderTexture.create(idx, ffi.sessionId, ffi);
  165. }
  166. if (!_gpuRenderTextures.containsKey(idx)) {
  167. final renderTexture = _GpuTexture();
  168. _gpuRenderTextures[idx] = renderTexture;
  169. renderTexture.create(idx, ffi.sessionId, ffi);
  170. }
  171. }
  172. tryRemoveTexture(int idx) {
  173. _control.remove(idx);
  174. if (_pixelbufferRenderTextures.containsKey(idx)) {
  175. _pixelbufferRenderTextures[idx]!.destroy(true, ffi);
  176. _pixelbufferRenderTextures.remove(idx);
  177. }
  178. if (_gpuRenderTextures.containsKey(idx)) {
  179. _gpuRenderTextures[idx]!.destroy(true, ffi);
  180. _gpuRenderTextures.remove(idx);
  181. }
  182. }
  183. if (curDisplay == kAllDisplayValue) {
  184. final displays = ffi.ffiModel.pi.getCurDisplays();
  185. for (var i = 0; i < displays.length; i++) {
  186. tryCreateTexture(i);
  187. }
  188. } else {
  189. tryCreateTexture(curDisplay);
  190. for (var i = 0; i < ffi.ffiModel.pi.displays.length; i++) {
  191. if (i != curDisplay) {
  192. tryRemoveTexture(i);
  193. }
  194. }
  195. }
  196. }
  197. onRemotePageDispose(bool closeSession) async {
  198. final ffi = parent.target;
  199. if (ffi == null) return;
  200. for (final texture in _pixelbufferRenderTextures.values) {
  201. await texture.destroy(closeSession, ffi);
  202. }
  203. for (final texture in _gpuRenderTextures.values) {
  204. await texture.destroy(closeSession, ffi);
  205. }
  206. }
  207. ensureControl(int display) {
  208. var ctl = _control[display];
  209. if (ctl == null) {
  210. ctl = _Control();
  211. _control[display] = ctl;
  212. }
  213. }
  214. }