| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/consts.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/models/model.dart'; | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import './platform_model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-22 13:16:37 +08:00
										 |  |  | import 'package:texture_rgba_renderer/texture_rgba_renderer.dart' | 
					
						
							|  |  |  |     if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-08 17:24:02 +08:00
										 |  |  | // Feature flutter_texture_render need to be enabled if feature gpucodec is enabled.
 | 
					
						
							| 
									
										
										
										
											2024-03-24 11:23:06 +08:00
										 |  |  | final useTextureRender = !isWeb && | 
					
						
							|  |  |  |     (bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender()); | 
					
						
							| 
									
										
										
										
											2023-10-08 21:44:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  | class _PixelbufferTexture { | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |   int _textureKey = -1; | 
					
						
							| 
									
										
										
										
											2023-10-08 21:44:54 +08:00
										 |  |  |   int _display = 0; | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |   SessionID? _sessionId; | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |   final support = bind.mainHasPixelbufferTextureRender(); | 
					
						
							|  |  |  |   bool _destroying = false; | 
					
						
							|  |  |  |   int? _id; | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final textureRenderer = TextureRgbaRenderer(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-08 21:44:54 +08:00
										 |  |  |   int get display => _display; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |   create(int d, SessionID sessionId, FFI ffi) { | 
					
						
							|  |  |  |     if (support) { | 
					
						
							| 
									
										
										
										
											2023-10-08 21:44:54 +08:00
										 |  |  |       _display = d; | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |       _textureKey = bind.getNextTextureKey(); | 
					
						
							|  |  |  |       _sessionId = sessionId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       textureRenderer.createTexture(_textureKey).then((id) async { | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |         _id = id; | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |         if (id != -1) { | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |           ffi.textureModel.setRgbaTextureId(display: d, id: id); | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |           final ptr = await textureRenderer.getTexturePtr(_textureKey); | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |           platformFFI.registerPixelbufferTexture(sessionId, display, ptr); | 
					
						
							|  |  |  |           debugPrint( | 
					
						
							|  |  |  |               "create pixelbuffer texture: peerId: ${ffi.id} display:$_display, textureId:$id"); | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |   destroy(bool unregisterTexture, FFI ffi) async { | 
					
						
							|  |  |  |     if (!_destroying && support && _textureKey != -1 && _sessionId != null) { | 
					
						
							|  |  |  |       _destroying = true; | 
					
						
							| 
									
										
										
										
											2023-08-14 20:40:58 +08:00
										 |  |  |       if (unregisterTexture) { | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |         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)); | 
					
						
							| 
									
										
										
										
											2023-08-14 20:40:58 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |       await textureRenderer.closeTexture(_textureKey); | 
					
						
							|  |  |  |       _textureKey = -1; | 
					
						
							| 
									
										
										
										
											2024-01-02 16:58:10 +08:00
										 |  |  |       _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(FFI ffi) async { | 
					
						
							|  |  |  |     // must stop texture render, render unregistered texture cause crash
 | 
					
						
							|  |  |  |     if (!_destroying && support && _sessionId != null && _textureId != -1) { | 
					
						
							|  |  |  |       _destroying = true; | 
					
						
							|  |  |  |       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"); | 
					
						
							|  |  |  |     var texture = _control[display]; | 
					
						
							|  |  |  |     if (texture == null) { | 
					
						
							|  |  |  |       texture = _Control(); | 
					
						
							|  |  |  |       _control[display] = texture; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     texture.setTextureType(gpuTexture: gpuTexture); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setRgbaTextureId({required int display, required int id}) { | 
					
						
							|  |  |  |     var ctl = _control[display]; | 
					
						
							|  |  |  |     if (ctl == null) { | 
					
						
							|  |  |  |       ctl = _Control(); | 
					
						
							|  |  |  |       _control[display] = ctl; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctl.setRgbaTextureId(id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setGpuTextureId({required int display, required int id}) { | 
					
						
							|  |  |  |     var ctl = _control[display]; | 
					
						
							|  |  |  |     if (ctl == null) { | 
					
						
							|  |  |  |       ctl = _Control(); | 
					
						
							|  |  |  |       _control[display] = ctl; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctl.setGpuTextureId(id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   RxInt getTextureId(int display) { | 
					
						
							|  |  |  |     var ctl = _control[display]; | 
					
						
							|  |  |  |     if (ctl == null) { | 
					
						
							|  |  |  |       ctl = _Control(); | 
					
						
							|  |  |  |       _control[display] = ctl; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ctl.textureID; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateCurrentDisplay(int curDisplay) { | 
					
						
							|  |  |  |     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(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(ffi); | 
					
						
							| 
									
										
										
										
											2023-08-01 22:19:38 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |