fix: move material/instance creation to render thread

This commit is contained in:
Nick Fisher
2024-12-16 15:25:19 +08:00
parent 7cf1468f38
commit 852cb58ba9
6 changed files with 158 additions and 162 deletions

View File

@@ -1,124 +0,0 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/thermion_dart.dart';
class ThermionFFIMaterialInstance extends MaterialInstance {
final Pointer<TMaterialInstance> pointer;
final Pointer<TSceneManager> sceneManager;
ThermionFFIMaterialInstance(this.pointer, this.sceneManager) {
if (pointer == nullptr) {
throw Exception("MaterialInstance not found");
}
}
@override
Future setDepthCullingEnabled(bool enabled) async {
MaterialInstance_setDepthCulling(this.pointer, enabled);
}
@override
Future setDepthWriteEnabled(bool enabled) async {
MaterialInstance_setDepthWrite(this.pointer, enabled);
}
@override
Future setParameterFloat4(
String name, double x, double y, double z, double w) async {
MaterialInstance_setParameterFloat4(
pointer, name.toNativeUtf8().cast<Char>(), x, y, z, w);
}
@override
Future setParameterFloat2(String name, double x, double y) async {
MaterialInstance_setParameterFloat2(
pointer, name.toNativeUtf8().cast<Char>(), x, y);
}
@override
Future setParameterFloat(String name, double value) async {
MaterialInstance_setParameterFloat(
pointer, name.toNativeUtf8().cast<Char>(), value);
}
@override
Future setParameterInt(String name, int value) async {
MaterialInstance_setParameterInt(
pointer, name.toNativeUtf8().cast<Char>(), value);
}
@override
Future setDepthFunc(SamplerCompareFunction depthFunc) async {
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]);
}
@override
Future setStencilOpDepthFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthFail(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilOpDepthStencilPass(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthStencilPass(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilOpStencilFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpStencilFail(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilReferenceValue(int value,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilReferenceValue(
pointer, value, TStencilFace.values[face.index]);
}
@override
Future setStencilWriteEnabled(bool enabled) async {
MaterialInstance_setStencilWrite(pointer, enabled);
}
@override
Future setCullingMode(CullingMode cullingMode) async {
MaterialInstance_setCullingMode(
pointer, TCullingMode.values[cullingMode.index]);
}
@override
Future<bool> isStencilWriteEnabled() async {
return MaterialInstance_isStencilWriteEnabled(pointer);
}
@override
Future setStencilReadMask(int mask) async {
MaterialInstance_setStencilReadMask(pointer, mask);
}
@override
Future setStencilWriteMask(int mask) async {
MaterialInstance_setStencilWriteMask(pointer, mask);
}
Future dispose() async {
SceneManager_destroyMaterialInstance(sceneManager, pointer);
}
}

View File

@@ -7,6 +7,12 @@ library;
import 'dart:ffi' as ffi;
@ffi.Native<ffi.Pointer<TMaterialInstance> Function(ffi.Pointer<TMaterial>)>(
isLeaf: true)
external ffi.Pointer<TMaterialInstance> Material_createInstance(
ffi.Pointer<TMaterial> tMaterial,
);
@ffi.Native<ffi.Bool Function(ffi.Pointer<TMaterialInstance>)>(isLeaf: true)
external bool MaterialInstance_isStencilWriteEnabled(
ffi.Pointer<TMaterialInstance> materialInstance,
@@ -372,6 +378,40 @@ external ffi.Pointer<TCamera> Engine_getCameraComponent(
int entityId,
);
@ffi.Native<ffi.Pointer<TTransformManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TTransformManager> Engine_getTransformManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<ffi.Pointer<TRenderableManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TRenderableManager> Engine_getRenderableManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<ffi.Pointer<TEntityManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TEntityManager> Engine_getEntityManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<
ffi.Pointer<TMaterial> Function(
ffi.Pointer<TEngine>, ffi.Pointer<ffi.Uint8>, ffi.Size)>(isLeaf: true)
external ffi.Pointer<TMaterial> Engine_buildMaterial(
ffi.Pointer<TEngine> tEngine,
ffi.Pointer<ffi.Uint8> materialData,
int length,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TEngine>, ffi.Pointer<TMaterial>)>(
isLeaf: true)
external void Engine_destroyMaterial(
ffi.Pointer<TEngine> tEngine,
ffi.Pointer<TMaterial> tMaterial,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>)>(isLeaf: true)
external void clear_background_image(
ffi.Pointer<TViewer> viewer,
@@ -558,24 +598,6 @@ external void queue_position_update_from_viewport_coords(
double viewportY,
);
@ffi.Native<ffi.Pointer<TTransformManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TTransformManager> Engine_getTransformManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<ffi.Pointer<TRenderableManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TRenderableManager> Engine_getRenderableManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<ffi.Pointer<TEntityManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TEntityManager> Engine_getEntityManager(
ffi.Pointer<TEngine> engine,
);
@ffi.Native<ffi.Void Function()>(isLeaf: true)
external void ios_dummy();
@@ -1288,6 +1310,46 @@ external void Viewer_createRenderTargetRenderThread(
onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TEngine>,
ffi.Pointer<ffi.Uint8>,
ffi.Size,
ffi.Pointer<
ffi
.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterial>)>>)>(
isLeaf: true)
external void Engine_buildMaterialRenderThread(
ffi.Pointer<TEngine> tEngine,
ffi.Pointer<ffi.Uint8> materialData,
int length,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterial>)>>
onComplete,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TEngine>, ffi.Pointer<TMaterial>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void Engine_destroyMaterialRenderThread(
ffi.Pointer<TEngine> tEngine,
ffi.Pointer<TMaterial> tMaterial,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TMaterial>,
ffi.Pointer<
ffi.NativeFunction<
ffi.Void Function(
ffi.Pointer<TMaterialInstance>)>>)>(isLeaf: true)
external void Material_createInstanceRenderThread(
ffi.Pointer<TMaterial> tMaterial,
ffi.Pointer<
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterialInstance>)>>
onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TView>, ffi.Pointer<TEngine>, ffi.Int)>(isLeaf: true)
@@ -1956,10 +2018,12 @@ external ffi.Pointer<TNameComponentManager>
ffi.Pointer<TSceneManager> tSceneManager,
);
@ffi.Native<ffi.Pointer<TSceneAsset> Function(ffi.Pointer<TSceneManager>)>(
isLeaf: true)
@ffi.Native<
ffi.Pointer<TSceneAsset> Function(
ffi.Pointer<TSceneManager>, ffi.Pointer<TMaterial>)>(isLeaf: true)
external ffi.Pointer<TSceneAsset> SceneManager_createGrid(
ffi.Pointer<TSceneManager> tSceneManager,
ffi.Pointer<TMaterial> tMaterial,
);
@ffi.Native<ffi.Bool Function(ffi.Pointer<TSceneManager>, EntityId)>(
@@ -2324,6 +2388,8 @@ final class TSceneAsset extends ffi.Opaque {}
final class TNameComponentManager extends ffi.Opaque {}
final class TMaterial extends ffi.Opaque {}
final class TMaterialInstance extends ffi.Opaque {}
final class TMaterialProvider extends ffi.Opaque {}

View File

@@ -5,16 +5,15 @@ import 'dart:typed_data';
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
import 'package:vector_math/vector_math_64.dart';
import 'package:vector_math/vector_math_64.dart' as v64;
import '../../../../utils/src/gizmo.dart';
import '../../../../utils/src/matrix.dart';
import '../../thermion_viewer_base.dart';
import 'package:logging/logging.dart';
import 'callbacks.dart';
import 'ffi_camera.dart';
import 'ffi_material_instance.dart';
import 'ffi_view.dart';
// ignore: constant_identifier_names
@@ -282,7 +281,7 @@ class ThermionViewerFFI extends ThermionViewer {
final _onDispose = <Future Function()>[];
bool _disposing = false;
final _materialInstances = <ThermionFFIMaterialInstance>[];
final _materialInstances = <FFIMaterialInstance>[];
///
///
@@ -1626,7 +1625,7 @@ class ThermionViewerFFI extends ThermionViewer {
0,
materialInstances.length,
materialInstances
.cast<ThermionFFIMaterialInstance>()
.cast<FFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
@@ -1760,8 +1759,13 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
///
Future showGridOverlay() async {
final ptr = SceneManager_createGrid(_sceneManager!);
Future showGridOverlay({FFIMaterial? material}) async {
late Pointer<TSceneAsset> ptr;
if (material == null) {
ptr = SceneManager_createGrid(_sceneManager!, nullptr);
} else {
ptr = SceneManager_createGrid(_sceneManager!, material.pointer);
}
_grid ??= FFIAsset(ptr, _sceneManager!, _engine!, _unlitMaterialProvider!);
await _grid!.addToScene();
}
@@ -1819,6 +1823,16 @@ class ThermionViewerFFI extends ThermionViewer {
destroy_texture(_sceneManager!, texture.pointer);
}
///
///
///
Future<Material> createMaterial(Uint8List data) async {
var ptr = await withPointerCallback<TMaterial>((cb) {
Engine_buildMaterialRenderThread(_engine!, data.address, data.length, cb);
});
return FFIMaterial(ptr, _engine!, _sceneManager!);
}
///
///
///
@@ -1905,8 +1919,7 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Failed to create material instance");
}
var instance =
ThermionFFIMaterialInstance(materialInstance, _sceneManager!);
var instance = FFIMaterialInstance(materialInstance, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
@@ -1914,8 +1927,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
///
Future destroyMaterialInstance(
ThermionFFIMaterialInstance materialInstance) async {
Future destroyMaterialInstance(FFIMaterialInstance materialInstance) async {
await materialInstance.dispose();
_materialInstances.remove(materialInstance);
}
@@ -1923,11 +1935,11 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
///
Future<ThermionFFIMaterialInstance> createUnlitMaterialInstance() async {
Future<FFIMaterialInstance> createUnlitMaterialInstance() async {
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb);
});
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
final instance = FFIMaterialInstance(instancePtr, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
@@ -1935,13 +1947,12 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
///
Future<ThermionFFIMaterialInstance>
createUnlitFixedSizeMaterialInstance() async {
Future<FFIMaterialInstance> createUnlitFixedSizeMaterialInstance() async {
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(
_sceneManager!, cb);
});
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
final instance = FFIMaterialInstance(instancePtr, _sceneManager!);
_materialInstances.add(instance);
return instance;
}
@@ -1954,7 +1965,7 @@ class ThermionViewerFFI extends ThermionViewer {
final instancePtr = RenderableManager_getMaterialInstanceAt(
_renderableManager!, entity, index);
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
final instance = FFIMaterialInstance(instancePtr, _sceneManager!);
return instance;
}
@@ -2065,8 +2076,8 @@ class ThermionViewerFFI extends ThermionViewer {
Future<GizmoAsset> createGizmo(FFIView view, GizmoType gizmoType) async {
var scene = View_getScene(view.view);
final gizmo = await withPointerCallback<TGizmo>((cb) {
SceneManager_createGizmoRenderThread(
_sceneManager!, view.view, scene, TGizmoType.values[gizmoType.index], cb);
SceneManager_createGizmoRenderThread(_sceneManager!, view.view, scene,
TGizmoType.values[gizmoType.index], cb);
});
if (gizmo == nullptr) {
throw Exception("Failed to create gizmo");

View File

@@ -72,6 +72,11 @@ enum StencilFace {
enum AlphaMode { OPAQUE, MASK, BLEND }
abstract class Material {
Future<MaterialInstance> createInstance();
Future dispose();
}
abstract class MaterialInstance {
Future<bool> isStencilWriteEnabled();
Future setDepthWriteEnabled(bool enabled);
@@ -110,4 +115,6 @@ abstract class MaterialInstance {
Future setStencilReadMask(int mask);
Future setStencilWriteMask(int mask);
Future dispose();
}

View File

@@ -40,6 +40,11 @@ namespace thermion
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *));
EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t* materialData, size_t length, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance*));
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping);
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom);
EMSCRIPTEN_KEEPALIVE void View_setCameraRenderThread(TView *tView, TCamera *tCamera, void (*callback)());

View File

@@ -280,6 +280,37 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t* materialData, size_t length, void (*onComplete)(TMaterial *)) {
std::packaged_task<void()> lambda(
[=]() mutable
{
auto material = Engine_buildMaterial(tEngine, materialData, length);
onComplete(material);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)()) {
std::packaged_task<void()> lambda(
[=]() mutable
{
Engine_destroyMaterial(tEngine, tMaterial);
onComplete();
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance*)) {
std::packaged_task<void()> lambda(
[=]() mutable
{
auto *instance = Material_createInstance(tMaterial);
onComplete(instance);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
set_frame_interval_render_thread(TViewer *viewer, float frameIntervalInMilliseconds)
{