From e25263ca3c00c0378d4bda75c74795910a58b198 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:27:52 +0200 Subject: [PATCH 1/5] Async shader compilation + shutdown --- Apps/UnitTests/Shared/Shared.cpp | 73 ++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/Apps/UnitTests/Shared/Shared.cpp b/Apps/UnitTests/Shared/Shared.cpp index ad1bb8b67..c8d9a23dc 100644 --- a/Apps/UnitTests/Shared/Shared.cpp +++ b/Apps/UnitTests/Shared/Shared.cpp @@ -134,6 +134,79 @@ TEST(NativeAPI, LifeCycle) } } */ +TEST(Shutdown, AsyncShaderCompilation) +{ + std::promise exitCodePromise; + + //for (int cycle = 0; cycle < 20; cycle++) + { + Babylon::Graphics::Device device{deviceConfig}; + auto update{ device.GetUpdate("update") }; + std::optional nativeCanvas; + + Babylon::AppRuntime runtime{}; + runtime.Dispatch([&device, &nativeCanvas, &exitCodePromise](Napi::Env env) { + device.AddToJavaScript(env); + + Babylon::Polyfills::XMLHttpRequest::Initialize(env); + Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) { + printf("%s", message); + fflush(stdout); + }); + Babylon::Polyfills::Window::Initialize(env); + + Babylon::Polyfills::XMLHttpRequest::Initialize(env); + + nativeCanvas.emplace(Babylon::Polyfills::Canvas::Initialize(env)); + + Babylon::Plugins::NativeEngine::Initialize(env); + + auto setExitCodeCallback = Napi::Function::New( + env, [&exitCodePromise](const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + exitCodePromise.set_value(info[0].As().Int32Value()); + }, "setExitCode"); + env.Global().Set("setExitCode", setExitCodeCallback); + }); + + Babylon::ScriptLoader loader{runtime}; + loader.LoadScript("app:///Scripts/babylon.max.js"); + loader.LoadScript("app:///Scripts/babylonjs.materials.js"); + loader.Eval(R"( + function CreateBoxAsync(scene) { + BABYLON.Mesh.CreateBox("box1", 0.2, scene); + return Promise.resolve(); + } + + var engine = new BABYLON.NativeEngine(); + var scene = new BABYLON.Scene(engine); + + CreateBoxAsync(scene).then(function () { + var disc = BABYLON.Mesh.CreateDisc("disc", 3, 60, scene); + + scene.createDefaultCamera(true, true, true); + scene.activeCamera.alpha += Math.PI; + scene.createDefaultLight(true); + + var mainMaterial = new BABYLON.PBRMaterial("main", scene); + disc.material = mainMaterial; + engine.runRenderLoop(function () { + scene.render(); + }); + setExitCode(1); + }, function (ex) { + console.log(ex.message, ex.stack); + }); + )", "script"); + + auto exitCode{ exitCodePromise.get_future().get() }; + device.StartRenderingCurrentFrame(); + update.Start(); + + update.Finish(); + device.FinishRenderingCurrentFrame(); + } +} TEST(Performance, Spheres) { From a818f07ad19e50db296ce22c26728048efc11af6 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:21:46 +0200 Subject: [PATCH 2/5] sleep_for because unable to expect a crash with gtest --- Apps/UnitTests/Shared/Shared.cpp | 105 +++++++++++-------------------- 1 file changed, 35 insertions(+), 70 deletions(-) diff --git a/Apps/UnitTests/Shared/Shared.cpp b/Apps/UnitTests/Shared/Shared.cpp index c8d9a23dc..74805c2c9 100644 --- a/Apps/UnitTests/Shared/Shared.cpp +++ b/Apps/UnitTests/Shared/Shared.cpp @@ -98,81 +98,43 @@ TEST(JavaScript, All) EXPECT_EQ(exitCode, 0); } -/* -This test does a serie of initialization and shutdowns. -It needs the shutdown PR to be merged before running properly. -TEST(NativeAPI, LifeCycle) -{ - for (int cycle = 0; cycle < 20; cycle++) - { - Babylon::Graphics::Device device{deviceConfig}; - std::optional nativeCanvas; - - Babylon::AppRuntime runtime{}; - runtime.Dispatch([&device, &nativeCanvas](Napi::Env env) { - device.AddToJavaScript(env); - - Babylon::Polyfills::XMLHttpRequest::Initialize(env); - Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) { - printf("%s", message); - fflush(stdout); - }); - Babylon::Polyfills::Window::Initialize(env); - nativeCanvas.emplace(Babylon::Polyfills::Canvas::Initialize(env)); - Babylon::Plugins::NativeEngine::Initialize(env); - }); - - Babylon::ScriptLoader loader{runtime}; - loader.LoadScript("app:///Scripts/babylon.max.js"); - loader.LoadScript("app:///Scripts/babylonjs.materials.js"); - - for (int frame = 0; frame < 10; frame++) - { - device.StartRenderingCurrentFrame(); - device.FinishRenderingCurrentFrame(); - } - } -} -*/ TEST(Shutdown, AsyncShaderCompilation) { std::promise exitCodePromise; - //for (int cycle = 0; cycle < 20; cycle++) - { - Babylon::Graphics::Device device{deviceConfig}; - auto update{ device.GetUpdate("update") }; - std::optional nativeCanvas; - - Babylon::AppRuntime runtime{}; - runtime.Dispatch([&device, &nativeCanvas, &exitCodePromise](Napi::Env env) { - device.AddToJavaScript(env); - - Babylon::Polyfills::XMLHttpRequest::Initialize(env); - Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) { - printf("%s", message); - fflush(stdout); + Babylon::Graphics::Device device{ deviceConfig }; + auto update{ device.GetUpdate("update") }; + std::optional nativeCanvas; + + Babylon::AppRuntime runtime{}; + runtime.Dispatch([&device, &nativeCanvas, &exitCodePromise](Napi::Env env) { + device.AddToJavaScript(env); + + Babylon::Polyfills::XMLHttpRequest::Initialize(env); + Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) { + std::cout << message << std::endl; + std::cout.flush(); }); - Babylon::Polyfills::Window::Initialize(env); + Babylon::Polyfills::Window::Initialize(env); - Babylon::Polyfills::XMLHttpRequest::Initialize(env); + Babylon::Polyfills::XMLHttpRequest::Initialize(env); - nativeCanvas.emplace(Babylon::Polyfills::Canvas::Initialize(env)); + nativeCanvas.emplace(Babylon::Polyfills::Canvas::Initialize(env)); - Babylon::Plugins::NativeEngine::Initialize(env); + Babylon::Plugins::NativeEngine::Initialize(env); - auto setExitCodeCallback = Napi::Function::New( - env, [&exitCodePromise](const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - exitCodePromise.set_value(info[0].As().Int32Value()); - }, "setExitCode"); - env.Global().Set("setExitCode", setExitCodeCallback); + auto setExitCodeCallback = Napi::Function::New( + env, [&exitCodePromise](const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + exitCodePromise.set_value(info[0].As().Int32Value()); + }, "setExitCode"); + env.Global().Set("setExitCode", setExitCodeCallback); }); - Babylon::ScriptLoader loader{runtime}; - loader.LoadScript("app:///Scripts/babylon.max.js"); - loader.LoadScript("app:///Scripts/babylonjs.materials.js"); - loader.Eval(R"( + Babylon::ScriptLoader loader{ runtime }; + loader.LoadScript("app:///Scripts/babylon.max.js"); + loader.LoadScript("app:///Scripts/babylonjs.materials.js"); + loader.Eval(R"( function CreateBoxAsync(scene) { BABYLON.Mesh.CreateBox("box1", 0.2, scene); return Promise.resolve(); @@ -199,13 +161,16 @@ TEST(Shutdown, AsyncShaderCompilation) }); )", "script"); - auto exitCode{ exitCodePromise.get_future().get() }; - device.StartRenderingCurrentFrame(); - update.Start(); + auto exitCode{ exitCodePromise.get_future().get() }; + device.StartRenderingCurrentFrame(); + update.Start(); - update.Finish(); - device.FinishRenderingCurrentFrame(); - } + update.Finish(); + device.FinishRenderingCurrentFrame(); + + // this sleep makes sure shader is finished loading/compiling before exit. + // Once shutdown is fixed, remove this sleep call. + std::this_thread::sleep_for(std::chrono::seconds(1)); } TEST(Performance, Spheres) From 654ae2af7c32df001b625c124cf326eeccb00f96 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:29:15 +0200 Subject: [PATCH 3/5] 5 seconds --- Apps/UnitTests/Shared/Shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/UnitTests/Shared/Shared.cpp b/Apps/UnitTests/Shared/Shared.cpp index 74805c2c9..dcc686ef4 100644 --- a/Apps/UnitTests/Shared/Shared.cpp +++ b/Apps/UnitTests/Shared/Shared.cpp @@ -170,7 +170,7 @@ TEST(Shutdown, AsyncShaderCompilation) // this sleep makes sure shader is finished loading/compiling before exit. // Once shutdown is fixed, remove this sleep call. - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::seconds(5)); } TEST(Performance, Spheres) From c159605e62fe64496b83ee4bed170d373f2b834b Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:38:04 +0200 Subject: [PATCH 4/5] 60s --- Apps/UnitTests/Shared/Shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/UnitTests/Shared/Shared.cpp b/Apps/UnitTests/Shared/Shared.cpp index dcc686ef4..080866907 100644 --- a/Apps/UnitTests/Shared/Shared.cpp +++ b/Apps/UnitTests/Shared/Shared.cpp @@ -170,7 +170,7 @@ TEST(Shutdown, AsyncShaderCompilation) // this sleep makes sure shader is finished loading/compiling before exit. // Once shutdown is fixed, remove this sleep call. - std::this_thread::sleep_for(std::chrono::seconds(5)); + std::this_thread::sleep_for(std::chrono::seconds(60)); } TEST(Performance, Spheres) From 9a5ebdc3a792d44aade45f3615a754bf41527662 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Fri, 14 Jun 2024 09:22:22 +0200 Subject: [PATCH 5/5] keep it as commented code --- Apps/UnitTests/Shared/Shared.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Apps/UnitTests/Shared/Shared.cpp b/Apps/UnitTests/Shared/Shared.cpp index 080866907..894f58a33 100644 --- a/Apps/UnitTests/Shared/Shared.cpp +++ b/Apps/UnitTests/Shared/Shared.cpp @@ -98,6 +98,9 @@ TEST(JavaScript, All) EXPECT_EQ(exitCode, 0); } +/* +Repro for shutdown scenario +Engine is shutdown before shader is finished compiling TEST(Shutdown, AsyncShaderCompilation) { std::promise exitCodePromise; @@ -167,11 +170,8 @@ TEST(Shutdown, AsyncShaderCompilation) update.Finish(); device.FinishRenderingCurrentFrame(); - - // this sleep makes sure shader is finished loading/compiling before exit. - // Once shutdown is fixed, remove this sleep call. - std::this_thread::sleep_for(std::chrono::seconds(60)); } +*/ TEST(Performance, Spheres) {