feat: support multiple ThermionWidget on Android

This commit is contained in:
Nick Fisher
2024-09-30 18:20:05 +08:00
parent e1efd5e4e0
commit 50ed0bdfda
25 changed files with 418 additions and 549 deletions

View File

@@ -15,6 +15,13 @@ extern "C" {
return window;
}
// int ThermionAndroid_createGLTexture(jobject )
// int ASurfaceTexture_attachToGLContext(
// ASurfaceTexture *st,
// uint32_t texName
// )
ResourceLoaderWrapper* make_resource_loader_wrapper_android(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void* owner) {
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
rlw->loadToOut = nullptr;

View File

@@ -25,6 +25,8 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.view.TextureRegistry.SurfaceTextureEntry
import java.io.File
import java.util.*
import android.opengl.GLES20;
class LoadFilamentResourceFromOwnerImpl(plugin:ThermionFlutterPlugin) : LoadFilamentResourceFromOwner {
var plugin = plugin
@@ -66,10 +68,18 @@ class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Lo
private var lifecycle: Lifecycle? = null
private lateinit var _lib : FilamentInterop
private data class TextureEntry(
val surfaceTextureEntry: SurfaceTextureEntry,
val surfaceTexture: SurfaceTexture,
val surface: Surface
)
var _surfaceTexture: SurfaceTexture? = null
private var _surfaceTextureEntry: SurfaceTextureEntry? = null
var _surface: Surface? = null
private val textures: MutableMap<Long, TextureEntry> = mutableMapOf()
private lateinit var activity:Activity
@@ -153,35 +163,55 @@ class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Lo
@RequiresApi(Build.VERSION_CODES.M)
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
Log.e("thermion_flutter", call.method, null)
when (call.method) {
"createTexture" -> {
if(_surfaceTextureEntry != null) {
result.error("TEXTURE_EXISTS", "Texture already exist. Make sure you call destroyTexture first", null)
return
}
val args = call.arguments as List<*>
val width = args[0] as Int
val height = args[1] as Int
if(width <1 || height < 1) {
result.error("DIMENSION_MISMATCH","Both dimensions must be greater than zero (you provided $width x $height)", null);
return;
}
Log.i("thermion_flutter", "Creating SurfaceTexture ${width}x${height}");
_surfaceTextureEntry = flutterPluginBinding.textureRegistry.createSurfaceTexture()
_surfaceTexture = _surfaceTextureEntry!!.surfaceTexture();
_surfaceTexture!!.setDefaultBufferSize(width, height)
val args = call.arguments as List<*>
val width = args[0] as Int
val height = args[1] as Int
if (width < 1 || height < 1) {
result.error("DIMENSION_MISMATCH", "Both dimensions must be greater than zero (you provided $width x $height)", null)
return
}
Log.i("thermion_flutter", "Creating SurfaceTexture ${width}x${height}")
val surfaceTextureEntry = flutterPluginBinding.textureRegistry.createSurfaceTexture()
val surfaceTexture = surfaceTextureEntry.surfaceTexture()
surfaceTexture.setDefaultBufferSize(width, height)
_surface = Surface(_surfaceTexture)
val surface = Surface(surfaceTexture)
if(!_surface!!.isValid) {
result.error("SURFACE_INVALID", "Failed to create valid surface", null)
} else {
val nativeWindow = _lib.get_native_window_from_surface(_surface!! as Object, JNIEnv.CURRENT)
result.success(listOf(_surfaceTextureEntry!!.id(), null, Pointer.nativeValue(nativeWindow)))
}
}
if (!surface.isValid) {
result.error("SURFACE_INVALID", "Failed to create valid surface", null)
} else {
val flutterTextureId = surfaceTextureEntry.id()
textures[flutterTextureId] = TextureEntry(surfaceTextureEntry, surfaceTexture, surface)
val nativeWindow = _lib.get_native_window_from_surface(surface as Object, JNIEnv.CURRENT)
result.success(listOf(flutterTextureId, flutterTextureId, Pointer.nativeValue(nativeWindow)))
}
}
"destroyTexture" -> {
val args = call.arguments as List<*>
val textureId = (args[0] as Int).toLong()
val textureEntry = textures[textureId]
if (textureEntry != null) {
textureEntry.surface.release()
textureEntry.surfaceTextureEntry.release()
textures.remove(textureId)
result.success(true)
} else {
result.error("TEXTURE_NOT_FOUND", "Texture with id $textureId not found", null)
}
}
"markTextureFrameAvailable" -> {
val textureId = (call.arguments as Int).toLong()
val textureEntry = textures[textureId]
if (textureEntry != null) {
//textureEntry.surfaceTexture.updateTexImage()
result.success(null)
} else {
result.error("TEXTURE_NOT_FOUND", "Texture with id $textureId not found", null)
}
}
"getResourceLoaderWrapper" -> {
val resourceLoader = _lib.make_resource_loader_wrapper_android(loadResourceWrapper, freeResourceWrapper, Pointer(0))
result.success(Pointer.nativeValue(resourceLoader))
@@ -196,13 +226,6 @@ class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Lo
val renderCallbackFnPointer = _lib.make_render_callback_fn_pointer(RenderCallbackImpl(this))
result.success(listOf(Pointer.nativeValue(renderCallbackFnPointer), 0))
}
"destroyTexture" -> {
_surface!!.release();
_surfaceTextureEntry!!.release();
_surface = null
_surfaceTextureEntry = null
result.success(true)
}
else -> {
result.notImplemented()
}
@@ -210,7 +233,13 @@ class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Lo
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
channel.setMethodCallHandler(null)
// Release all textures
for ((_, textureEntry) in textures) {
textureEntry.surface.release()
textureEntry.surfaceTextureEntry.release()
}
textures.clear()
}

View File

@@ -50,13 +50,8 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
var width = (size.width * dpr).ceil();
var height = (size.height * dpr).ceil();
_texture =
await ThermionFlutterPlatform.instance.createTexture(width, height);
_renderTarget = await widget.viewer.createRenderTarget(
_texture!.width, _texture!.height, _texture!.hardwareId);
await widget.view.setRenderTarget(_renderTarget!);
_texture = await ThermionFlutterPlatform.instance
.createTexture(widget.view, width, height);
await widget.view.updateViewport(_texture!.width, _texture!.height);
var camera = await widget.view.getCamera();
@@ -74,13 +69,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
if (mounted) {
setState(() {});
}
if (texture != null) {
_renderTarget = await widget.viewer.createRenderTarget(
texture.width, texture.height, texture.flutterId);
await widget.view.setRenderTarget(null);
await _renderTarget!.destroy();
texture.destroy();
}
await texture?.destroy();
_views.clear();
});
});
@@ -100,7 +89,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
WidgetsBinding.instance.scheduleFrameCallback((d) async {
if (widget.viewer.rendering && !_rendering) {
_rendering = true;
if (_callbackId == _primaryCallback) {
if (_callbackId == _primaryCallback && _texture != null) {
await widget.viewer.requestFrame();
lastRender = d.inMilliseconds;
}
@@ -140,8 +129,6 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
var newWidth = newSize.width.ceil();
var newHeight = newSize.height.ceil();
var lastTextureId = _texture?.hardwareId;
await _texture?.resize(
newWidth,
newHeight,
@@ -149,12 +136,6 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
0,
);
if (_texture?.hardwareId != lastTextureId) {
await _renderTarget?.destroy();
_renderTarget = await widget.viewer.createRenderTarget(
_texture!.width, _texture!.height, _texture!.hardwareId);
await widget.view.setRenderTarget(_renderTarget!);
}
await widget.view.updateViewport(_texture!.width, _texture!.height);
var camera = await widget.view.getCamera();