fix: store reference to material instances in ThermionViewer so they can be cleaned up on dispose

This commit is contained in:
Nick Fisher
2024-11-27 14:19:18 +08:00
parent bedd50ec38
commit c2077cb6b1
7 changed files with 101 additions and 51 deletions

View File

@@ -122,7 +122,7 @@ class FFIAsset extends ThermionAsset {
}
var sourceMaterialInstance = ThermionFFIMaterialInstance(
RenderableManager_getMaterialInstanceAt(
renderableManager, targetEntity, 0));
renderableManager, targetEntity, 0), sceneManager);
await sourceMaterialInstance.setStencilWriteEnabled(true);
await sourceMaterialInstance.setDepthWriteEnabled(true);
@@ -138,7 +138,7 @@ class FFIAsset extends ThermionAsset {
_unlitMaterialProvider, key.address, cb);
});
final highlightMaterialInstance =
ThermionFFIMaterialInstance(materialInstancePtr);
ThermionFFIMaterialInstance(materialInstancePtr, sceneManager);
await highlightMaterialInstance
.setStencilCompareFunction(SamplerCompareFunction.NE);
await highlightMaterialInstance.setStencilReferenceValue(1);

View File

@@ -6,8 +6,9 @@ import 'package:thermion_dart/thermion_dart.dart';
class ThermionFFIMaterialInstance extends MaterialInstance {
final Pointer<TMaterialInstance> pointer;
final Pointer<TSceneManager> sceneManager;
ThermionFFIMaterialInstance(this.pointer) {
ThermionFFIMaterialInstance(this.pointer, this.sceneManager) {
if (pointer == nullptr) {
throw Exception("MaterialInstance not found");
}
@@ -50,14 +51,17 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
@override
Future setDepthFunc(SamplerCompareFunction depthFunc) async {
MaterialInstance_setDepthFunc(pointer, TSamplerCompareFunc.values[depthFunc.index]);
MaterialInstance_setDepthFunc(
pointer, TSamplerCompareFunc.values[depthFunc.index]);
}
@override
Future setStencilCompareFunction(SamplerCompareFunction func,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilCompareFunction(
pointer, TSamplerCompareFunc.values[func.index], TStencilFace.values[face.index]);
pointer,
TSamplerCompareFunc.values[func.index],
TStencilFace.values[face.index]);
}
@override
@@ -113,4 +117,8 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
Future setStencilWriteMask(int mask) async {
MaterialInstance_setStencilWriteMask(pointer, mask);
}
Future dispose() async {
SceneManager_destroyMaterialInstance(sceneManager, pointer);
}
}

View File

@@ -282,6 +282,8 @@ class ThermionViewerFFI extends ThermionViewer {
final _onDispose = <Future Function()>[];
bool _disposing = false;
final _materialInstances = <ThermionFFIMaterialInstance>[];
///
///
///
@@ -291,12 +293,13 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Viewer has already been disposed.");
}
_disposing = true;
await setRendering(false);
await clearEntities();
for (final mInstance in _materialInstances) {
await mInstance.dispose();
}
await clearLights();
// await _sceneUpdateEventController.close();
Viewer_destroyOnRenderThread(_viewer!);
_sceneManager = null;
_viewer = null;
@@ -984,9 +987,6 @@ class ThermionViewerFFI extends ThermionViewer {
_sceneManager!, asset.pointer, callback));
}
///
///
///
///
///
///
@@ -1880,7 +1880,10 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Failed to create material instance");
}
return ThermionFFIMaterialInstance(materialInstance);
var instance =
ThermionFFIMaterialInstance(materialInstance, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
///
@@ -1888,21 +1891,20 @@ class ThermionViewerFFI extends ThermionViewer {
///
Future destroyMaterialInstance(
ThermionFFIMaterialInstance materialInstance) async {
SceneManager_destroyMaterialInstance(
_sceneManager!, materialInstance.pointer);
await materialInstance.dispose();
_materialInstances.remove(materialInstance);
}
///
///
///
Future<ThermionFFIMaterialInstance> createUnlitMaterialInstance() async {
var instance = await withPointerCallback<TMaterialInstance>((cb) {
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb);
});
if (instance == nullptr) {
throw Exception("Failed to create material instance");
}
return ThermionFFIMaterialInstance(instance);
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
///
@@ -1910,14 +1912,13 @@ class ThermionViewerFFI extends ThermionViewer {
///
Future<ThermionFFIMaterialInstance>
createUnlitFixedSizeMaterialInstance() async {
var instance = await withPointerCallback<TMaterialInstance>((cb) {
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(
_sceneManager!, cb);
});
if (instance == nullptr) {
throw Exception("Failed to create material instance");
}
return ThermionFFIMaterialInstance(instance);
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
///
@@ -1925,12 +1926,11 @@ class ThermionViewerFFI extends ThermionViewer {
///
Future<MaterialInstance> getMaterialInstanceAt(
ThermionEntity entity, int index) async {
final instance = RenderableManager_getMaterialInstanceAt(
final instancePtr = RenderableManager_getMaterialInstanceAt(
_renderableManager!, entity, index);
if (instance == nullptr) {
throw Exception("Failed to get material instance");
}
return ThermionFFIMaterialInstance(instance);
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
return instance;
}
@override
@@ -2036,8 +2036,8 @@ class ThermionViewerFFI extends ThermionViewer {
SceneManager_getOverlayEntityCount(_sceneManager!);
final overlayEntities = List<ThermionEntity>.generate(overlayEntityCount,
(i) => SceneManager_getOverlayEntityAt(_sceneManager!, i)).toSet();
return FFIGizmo(
view, gizmo.cast<TSceneAsset>(), _sceneManager!, _engine!, nullptr, overlayEntities);
return FFIGizmo(view, gizmo.cast<TSceneAsset>(), _sceneManager!, _engine!,
nullptr, overlayEntities);
}
}

View File

@@ -67,7 +67,7 @@ enum StencilFace {
BACK,
/// Both front and back faces
FRONT_AND_BACK
FRONT_AND_BACK
}
enum AlphaMode { OPAQUE, MASK, BLEND }
@@ -109,4 +109,5 @@ abstract class MaterialInstance {
Future setStencilReadMask(int mask);
Future setStencilWriteMask(int mask);
}

View File

@@ -792,28 +792,28 @@ abstract class ThermionViewer {
AlphaMode alphaMode = AlphaMode.OPAQUE,
bool enableDiagnostics = false,
bool hasMetallicRoughnessTexture = false,
int metallicRoughnessUV = 0,
int baseColorUV = 0,
int metallicRoughnessUV = -1,
int baseColorUV = -1,
bool hasClearCoatTexture = false,
int clearCoatUV = 0,
int clearCoatUV = -1,
bool hasClearCoatRoughnessTexture = false,
int clearCoatRoughnessUV = 0,
int clearCoatRoughnessUV = -1,
bool hasClearCoatNormalTexture = false,
int clearCoatNormalUV = 0,
int clearCoatNormalUV = -1,
bool hasClearCoat = false,
bool hasTransmission = false,
bool hasTextureTransforms = false,
int emissiveUV = 0,
int aoUV = 0,
int normalUV = 0,
int emissiveUV = -1,
int aoUV = -1,
int normalUV = -1,
bool hasTransmissionTexture = false,
int transmissionUV = 0,
int transmissionUV = -1,
bool hasSheenColorTexture = false,
int sheenColorUV = 0,
int sheenColorUV = -1,
bool hasSheenRoughnessTexture = false,
int sheenRoughnessUV = 0,
int sheenRoughnessUV = -1,
bool hasVolumeThicknessTexture = false,
int volumeThicknessUV = 0,
int volumeThicknessUV = -1,
bool hasSheen = false,
bool hasIOR = false,
bool hasVolume = false,