diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index fe788e3ae..56318115a 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -26,12 +26,22 @@ jobs: distribution: temurin java-version: '17' + - name: Install Ninja (Hermes host-compiler bootstrap) + if: inputs.js-engine == 'Hermes' + run: | + if [ "${{ runner.os }}" = "Linux" ]; then + sudo apt-get update + sudo apt-get install -y ninja-build + elif [ "${{ runner.os }}" = "macOS" ] && ! command -v ninja >/dev/null 2>&1; then + brew install ninja + fi + - name: Build Playground ${{ inputs.js-engine }} working-directory: Apps/Playground/Android run: | chmod +x gradlew ./gradlew assembleRelease \ - -PJSEngine=${{ inputs.js-engine }} \ + -PjsEngine=${{ inputs.js-engine }} \ -PARM64Only \ -PNDK_VERSION=${{ env.NDK_VERSION }} \ -PSANITIZERS=OFF diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 4a9eaff07..36d410277 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -24,7 +24,7 @@ env: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: ${{ inputs.js-engine == 'Hermes' && 60 || 30 }} env: CC: ${{ inputs.cc }} CXX: ${{ inputs.cxx }} @@ -46,6 +46,7 @@ jobs: -D BX_CONFIG_DEBUG=ON \ -D OpenGL_GL_PREFERENCE=GLVND \ -D BABYLON_DEBUG_TRACE=ON \ + ${{ inputs.js-engine == 'Hermes' && '-D HERMES_UNICODE_LITE=ON -D HERMES_ALLOW_BOOST_CONTEXT=0' || '' }} \ -D ENABLE_SANITIZERS=${{ inputs.enable-sanitizers && 'ON' || 'OFF' }} . ninja -C build/Linux diff --git a/.github/workflows/build-win32.yml b/.github/workflows/build-win32.yml index 6173cc34f..eb82324b1 100644 --- a/.github/workflows/build-win32.yml +++ b/.github/workflows/build-win32.yml @@ -39,6 +39,9 @@ jobs: elif [ "${{ inputs.napi-type }}" = "V8" ]; then SUFFIX="_V8" JS_DEFINE="-DNAPI_JAVASCRIPT_ENGINE=V8" + elif [ "${{ inputs.napi-type }}" = "Hermes" ]; then + SUFFIX="_Hermes" + JS_DEFINE="-DNAPI_JAVASCRIPT_ENGINE=Hermes -DHERMES_ALLOW_BOOST_CONTEXT=0" fi echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT" echo "js_define=$JS_DEFINE" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a466d0c0a..b91d2c4b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,6 +64,12 @@ jobs: platform: x64 napi-type: V8 + Win32_x64_Hermes_D3D11: + uses: ./.github/workflows/build-win32.yml + with: + platform: x64 + napi-type: Hermes + Win32_x64_D3D11_Sanitizers: uses: ./.github/workflows/build-win32.yml with: @@ -104,6 +110,13 @@ jobs: cxx: clang++ js-engine: JavaScriptCore + Ubuntu_Clang_Hermes: + uses: ./.github/workflows/build-linux.yml + with: + cc: clang + cxx: clang++ + js-engine: Hermes + Ubuntu_GCC_JSC: uses: ./.github/workflows/build-linux.yml with: @@ -124,6 +137,12 @@ jobs: runs-on: ubuntu-latest js-engine: V8 + Android_Ubuntu_Hermes: + uses: ./.github/workflows/build-android.yml + with: + runs-on: ubuntu-latest + js-engine: Hermes + Android_MacOS_JSC: uses: ./.github/workflows/build-android.yml with: diff --git a/Apps/ModuleLoadTest/Source/App.X11.cpp b/Apps/ModuleLoadTest/Source/App.X11.cpp index 92193cec2..e6d39f618 100644 --- a/Apps/ModuleLoadTest/Source/App.X11.cpp +++ b/Apps/ModuleLoadTest/Source/App.X11.cpp @@ -56,6 +56,9 @@ namespace ModuleLoadTest "libexpat.so.1", "libgbm.so.1", "libgldispatch.so.0", + "libicudata.so.74", + "libicuuc.so.74", + "liblzma.so.5", "libpciaccess.so.0", "libsensors.so.5", "libtinfo.so.6", diff --git a/Apps/Playground/Android/BabylonNative/build.gradle b/Apps/Playground/Android/BabylonNative/build.gradle index e58833292..3f075645d 100644 --- a/Apps/Playground/Android/BabylonNative/build.gradle +++ b/Apps/Playground/Android/BabylonNative/build.gradle @@ -18,6 +18,25 @@ if (project.hasProperty("GRAPHICS_API")) { def arcore_libpath = layout.buildDirectory.dir("arcore-native").get().asFile.absolutePath +def cmakeArguments = [ + "-DANDROID_STL=c++_shared", + "-DENABLE_PCH=OFF", + "-DGRAPHICS_API=${graphics_api}", + "-DARCORE_LIBPATH=${arcore_libpath}/jni", + "-DNAPI_JAVASCRIPT_ENGINE=${jsEngine}", + "-DBABYLON_NATIVE_BUILD_APPS=ON", + "-DBABYLON_DEBUG_TRACE=ON" +] +// Hermes for Android needs HOST hermesc/shermes (they emit bytecode at build +// time and can't run as NDK-cross-compiled binaries). JsRuntimeHost's CMake +// bootstraps these host compilers automatically when cross-compiling, so no +// hand-off is normally required. This property is an optional manual override: +// pass -PimportHostCompilers= to reuse a prebuilt +// host-compiler set and skip the in-CMake bootstrap. +if (project.hasProperty("importHostCompilers")) { + cmakeArguments.add("-DIMPORT_HOST_COMPILERS=${project.property('importHostCompilers')}") +} + configurations { natives } android { @@ -36,13 +55,7 @@ android { externalNativeBuild { cmake { abiFilters "arm64-v8a", "armeabi-v7a", "x86", "x86_64" - arguments "-DANDROID_STL=c++_shared", - "-DENABLE_PCH=OFF", - "-DGRAPHICS_API=${graphics_api}", - "-DARCORE_LIBPATH=${arcore_libpath}/jni", - "-DNAPI_JAVASCRIPT_ENGINE=${jsEngine}", - "-DBABYLON_NATIVE_BUILD_APPS=ON", - "-DBABYLON_DEBUG_TRACE=ON" + arguments(*cmakeArguments) cppFlags += ["-Wno-deprecated-literal-operator"] } } diff --git a/Apps/Playground/Scripts/validation_native.js b/Apps/Playground/Scripts/validation_native.js index 0b75478a8..e691600ad 100644 --- a/Apps/Playground/Scripts/validation_native.js +++ b/Apps/Playground/Scripts/validation_native.js @@ -81,6 +81,7 @@ } const engine = new BABYLON.NativeEngine(); + globalThis.engine = engine; engine.getCaps().parallelShaderCompile = undefined; // Broaden Babylon's default retry strategy for the test framework: in addition to @@ -113,6 +114,7 @@ } const canvas = window; + globalThis.canvas = canvas; // Random replacement let seed = 1; diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e23181a3..dc82dc98f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,8 +53,8 @@ FetchContent_Declare(ios-cmake GIT_TAG 4.5.0 EXCLUDE_FROM_ALL) FetchContent_Declare(JsRuntimeHost - GIT_REPOSITORY https://github.com/BabylonJS/JsRuntimeHost.git - GIT_TAG 272f6a9f3de78f7c4cd8a838ae9655c81fc4881a) + GIT_REPOSITORY https://github.com/CedricGuillemet/JsRuntimeHost.git + GIT_TAG hermes-integration) FetchContent_Declare(metal-cpp GIT_REPOSITORY https://github.com/bkaradzic/metal-cpp.git GIT_TAG metal-cpp_26 diff --git a/Embedding/Source/Runtime.cpp b/Embedding/Source/Runtime.cpp index 5a7acfa88..852528288 100644 --- a/Embedding/Source/Runtime.cpp +++ b/Embedding/Source/Runtime.cpp @@ -182,6 +182,13 @@ namespace Babylon::Embedding #endif m_appRuntime->Dispatch([implPtr = this, window](Napi::Env env) { + // 0. Install the ES2020 `globalThis` self-reference. V8/JSC/Chakra + // provide it intrinsically, but the embedded Hermes runtime does + // not, and Hermes evaluates eval()'d code as indirect (global + // scope) eval -- so browser-style snippets can only reach host + // state through properties of the global object. + env.Global().Set("globalThis", env.Global()); + // 1. Make the Device available to JS. implPtr->m_device->AddToJavaScript(env); @@ -225,6 +232,10 @@ namespace Babylon::Embedding #if BABYLON_NATIVE_POLYFILL_WINDOW Babylon::Polyfills::Window::Initialize(env); + // Alias `canvas` to the global object so playground snippets that + // reference a bare `canvas` global resolve under Hermes indirect + // eval (mirrors the `window` polyfill). + env.Global().Set("canvas", env.Global()); #endif Babylon::Polyfills::TextDecoder::Initialize(env);