diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart index 453cd782..11d54e45 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart @@ -1396,6 +1396,12 @@ external int TransformManager_getAncestor( int childEntityId, ); +@ffi.Native(isLeaf: true) +external void RenderLoop_create(); + +@ffi.Native(isLeaf: true) +external void RenderLoop_destroy(); + @ffi.Native< ffi.Void Function( ffi.Pointer, diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart index 0cbdcd8a..59265622 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart @@ -179,6 +179,11 @@ class ThermionViewerFFI extends ThermionViewer { } Future _initialize() async { + _logger.info("Initializing ThermionViewerFFI"); + + RenderLoop_destroy(); + RenderLoop_create(); + final uberarchivePtr = uberArchivePath?.toNativeUtf8(allocator: allocator).cast() ?? nullptr; @@ -205,6 +210,7 @@ class ThermionViewerFFI extends ThermionViewer { _nameComponentManager = SceneManager_getNameComponentManager(_sceneManager!); _renderableManager = Engine_getRenderableManager(_engine!); + this._initialized.complete(true); } @@ -302,14 +308,17 @@ class ThermionViewerFFI extends ThermionViewer { await mInstance.dispose(); } await destroyLights(); - Viewer_destroyOnRenderThread(_viewer!); + + RenderLoop_destroy(); + _sceneManager = null; _viewer = null; for (final callback in _onDispose) { await callback.call(); } + _onDispose.clear(); _disposing = false; } @@ -2194,7 +2203,8 @@ class ThermionViewerFFI extends ThermionViewer { /// /// Future setReceiveShadows(ThermionEntity entity, bool receiveShadows) async { - RenderableManager_setReceiveShadows(_renderableManager!, entity, receiveShadows); + RenderableManager_setReceiveShadows( + _renderableManager!, entity, receiveShadows); } /// diff --git a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h index e61ac899..1d690728 100644 --- a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h @@ -22,6 +22,9 @@ namespace thermion typedef int32_t EntityId; typedef void (*FilamentRenderCallback)(void *const owner); + EMSCRIPTEN_KEEPALIVE void RenderLoop_create(); + EMSCRIPTEN_KEEPALIVE void RenderLoop_destroy(); + EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread( void *const context, void *const platform, diff --git a/thermion_dart/native/src/FilamentViewer.cpp b/thermion_dart/native/src/FilamentViewer.cpp index 3be3a235..743152b7 100644 --- a/thermion_dart/native/src/FilamentViewer.cpp +++ b/thermion_dart/native/src/FilamentViewer.cpp @@ -516,9 +516,8 @@ namespace thermion FilamentViewer::~FilamentViewer() { - + TRACE("Destroying FilamentViewer"); _sceneManager->destroyAll(); - for (auto view : _views) { view->setRenderTarget(nullptr); @@ -526,20 +525,20 @@ namespace thermion } _views.clear(); - + TRACE("Destroying render targets"); for(auto rt : _renderTargets) { destroyRenderTarget(rt); } _renderTargets.clear(); - + TRACE("Destroying swapchains"); for (auto swapChain : _swapChains) { _engine->destroy(swapChain); } _swapChains.clear(); - + TRACE("Destroying background image"); if (!_imageEntity.isNull()) { _engine->destroy(_imageEntity); @@ -548,13 +547,18 @@ namespace thermion _engine->destroy(_imageIb); _engine->destroy(_imageMaterial); } + TRACE("Destroying SceneManager"); delete _sceneManager; + TRACE("SceneManager destroyed"); _engine->destroyCameraComponent(_mainCamera->getEntity()); _mainCamera = nullptr; _engine->destroy(_scene); _engine->destroy(_renderer); + TRACE("Destroying engine"); Engine::destroy(&_engine); + TRACE("Engine destroyed"); delete _resourceLoaderWrapper; + TRACE("Destruction complete."); } Renderer *FilamentViewer::getRenderer() { return _renderer; } diff --git a/thermion_dart/native/src/c_api/ThermionDartApi.cpp b/thermion_dart/native/src/c_api/ThermionDartApi.cpp index c96e5aee..5ac8a446 100644 --- a/thermion_dart/native/src/c_api/ThermionDartApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartApi.cpp @@ -49,9 +49,10 @@ extern "C" viewer->destroyRenderTarget(renderTarget); } - EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer) + EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *tViewer) { - delete ((FilamentViewer *)viewer); + auto *viewer = reinterpret_cast(tViewer); + delete viewer; } EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a) diff --git a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp index d2fbb30c..dce1b31e 100644 --- a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp @@ -35,20 +35,12 @@ public: ~RenderLoop() { + TRACE("Destroying RenderLoop"); _stop = true; _cv.notify_one(); + TRACE("Joining RenderLoop thread.."); t->join(); - } - - static void mainLoop(void *arg) - { - ((RenderLoop *)arg)->iter(); - } - - static void *startHelper(void *parm) - { - ((RenderLoop *)parm)->start(); - return nullptr; + TRACE("RenderLoop destructor complete"); } void start() @@ -59,6 +51,42 @@ public: } } + void destroyViewer() { + std::packaged_task lambda([=]() mutable + { + if(viewer) { + Viewer_destroy(viewer); + } + viewer = nullptr; + _renderCallback = nullptr; + _renderCallbackOwner = nullptr; + + }); + auto fut = add_task(lambda); + fut.wait(); + } + + void createViewer( + void *const context, + void *const platform, + const char *uberArchivePath, + const void *const loader, + void (*renderCallback)(void *), + void *const owner, + void (*callback)(TViewer *)) + { + _renderCallback = renderCallback; + _renderCallbackOwner = owner; + std::packaged_task lambda([=]() mutable + { + if(viewer) { + Viewer_destroy(viewer); + } + viewer = Viewer_create(context, loader, platform, uberArchivePath); + callback(viewer); }); + add_task(lambda); + } + void requestFrame(void (*callback)()) { std::unique_lock lock(_mutex); @@ -109,37 +137,9 @@ public: { return !_tasks.empty() || _stop; }); } - void createViewer(void *const context, - void *const platform, - const char *uberArchivePath, - const ResourceLoaderWrapper *const loader, - void (*renderCallback)(void *), - void *const owner, - void (*callback)(TViewer *)) - { - _renderCallback = renderCallback; - _renderCallbackOwner = owner; - std::packaged_task lambda([=]() mutable - { - auto viewer = (FilamentViewer *)Viewer_create(context, loader, platform, uberArchivePath); - _viewer = reinterpret_cast(viewer); - callback(_viewer); }); - auto fut = add_task(lambda); - } - - void destroyViewer(FilamentViewer *viewer) - { - std::packaged_task lambda([=]() mutable - { - _viewer = nullptr; - Viewer_destroy(reinterpret_cast(viewer)); }); - auto fut = add_task(lambda); - fut.wait(); - } - void doRender() { - Viewer_render(_viewer); + Viewer_render(viewer); if (_renderCallback) { _renderCallback(_renderCallbackOwner); @@ -163,6 +163,8 @@ public: return ret; } + TViewer *viewer = std::nullptr_t(); + private: void (*_requestFrameRenderCallback)() = nullptr; bool _stop = false; @@ -173,7 +175,6 @@ private: void (*_renderCallback)(void *const) = nullptr; void *_renderCallbackOwner = nullptr; std::deque> _tasks; - TViewer *_viewer = nullptr; std::chrono::high_resolution_clock::time_point _lastFrameTime; int _frameCount = 0; float _accumulatedTime = 0.0f; @@ -184,7 +185,25 @@ private: extern "C" { - static RenderLoop *_rl; + static std::unique_ptr _rl; + + EMSCRIPTEN_KEEPALIVE void RenderLoop_create() { + TRACE("RenderLoop_create"); + if (_rl) + { + Log("WARNING - you are attempting to create a RenderLoop when the previous one has not been disposed."); + } + _rl = std::make_unique(); + } + + EMSCRIPTEN_KEEPALIVE void RenderLoop_destroy() { + TRACE("RenderLoop_destroy"); + if (_rl) + { + _rl->destroyViewer(); + _rl = nullptr; + } + } EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread( void *const context, void *const platform, const char *uberArchivePath, @@ -193,20 +212,27 @@ extern "C" void *const renderCallbackOwner, void (*callback)(TViewer *)) { - - if (!_rl) - { - _rl = new RenderLoop(); - } - _rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader, - renderCallback, renderCallbackOwner, callback); + TRACE("Viewer_createOnRenderThread"); + _rl->createViewer( + context, + platform, + uberArchivePath, + loader, + renderCallback, + renderCallbackOwner, + callback + ); } EMSCRIPTEN_KEEPALIVE void Viewer_destroyOnRenderThread(TViewer *viewer) { - _rl->destroyViewer((FilamentViewer *)viewer); - delete _rl; - _rl = nullptr; + TRACE("Viewer_destroyOnRenderThread"); + if (!_rl) + { + Log("Warning - cannot destroy viewer, no RenderLoop has been created"); + } else { + _rl->destroyViewer(); + } } EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, @@ -320,14 +346,15 @@ extern "C" auto fut = _rl->add_task(lambda); } - EMSCRIPTEN_KEEPALIVE void Engine_destroyTextureRenderThread(TEngine *engine, TTexture* tTexture, void (*onComplete)()) { + EMSCRIPTEN_KEEPALIVE void Engine_destroyTextureRenderThread(TEngine *engine, TTexture *tTexture, void (*onComplete)()) + { std::packaged_task lambda( - [=]() mutable - { - Engine_destroyTexture(engine, tTexture); - onComplete(); - }); - auto fut = _rl->add_task(lambda); + [=]() mutable + { + Engine_destroyTexture(engine, tTexture); + onComplete(); + }); + auto fut = _rl->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *)) diff --git a/thermion_dart/native/src/scene/SceneManager.cpp b/thermion_dart/native/src/scene/SceneManager.cpp index 806709a7..55d51e9a 100644 --- a/thermion_dart/native/src/scene/SceneManager.cpp +++ b/thermion_dart/native/src/scene/SceneManager.cpp @@ -124,17 +124,21 @@ namespace thermion SceneManager::~SceneManager() { + TRACE("Destroying cameras"); for (auto camera : _cameras) { auto entity = camera->getEntity(); _engine->destroyCameraComponent(entity); _engine->getEntityManager().destroy(entity); } + TRACE("Cameras destroyed"); destroyAll(); + TRACE("Destroyed all assets"); _engine->destroy(_unlitFixedSizeMaterial); _engine->destroy(_gizmoMaterial); + TRACE("Destroyed materials"); _cameras.clear(); _grid = nullptr; @@ -150,7 +154,9 @@ namespace thermion delete _stbDecoder; delete _ktxDecoder; delete _ubershaderProvider; + TRACE("Destroying asset loader"); AssetLoader::destroy(&_assetLoader); + TRACE("Destroyed asset loader"); } SceneAsset *SceneManager::createGrid(Material *material)