Skip to content

Commit b83bd3c

Browse files
committed
w
1 parent b925dfd commit b83bd3c

9 files changed

+235
-10
lines changed

.github/workflows/linux-wasm-ci-build-and-test-workflow.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ jobs:
105105
${{ env.common_build_args }} \
106106
--build_dir ${{ github.workspace }}/build/wasm_inferencing_webgpu \
107107
--use_webgpu \
108-
--use_jsep \
109108
--use_webnn \
110109
--target onnxruntime_webassembly \
111110
--skip_tests

build_release_jsep.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
call build.bat --parallel --config Release --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads --target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti --build_dir C:\code\o2\build_jsep_rel\ --use_jsep --use_webnn --target onnxruntime_webassembly --skip_tests

build_release_webgpu.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
call build.bat --parallel --config Release --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads --target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti --build_dir C:\code\o2\build_webgpu_rel\ --use_webgpu --use_webnn --target onnxruntime_webassembly --skip_tests

cmake/onnxruntime_webassembly.cmake

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ function(bundle_static_library bundled_target_name)
8484
add_dependencies(${bundled_target_name} bundling_target)
8585
endfunction()
8686

87+
if (onnxruntime_USE_JSEP AND onnxruntime_USE_WEBGPU)
88+
message(FATAL_ERROR "onnxruntime_USE_JSEP and onnxruntime_USE_WEBGPU cannot be enabled at the same time.")
89+
endif()
90+
8791
if (NOT onnxruntime_ENABLE_WEBASSEMBLY_THREADS)
8892
add_compile_definitions(
8993
BUILD_MLAS_NO_ONNXRUNTIME
@@ -406,6 +410,16 @@ jsepDownload:_pp_")
406410
list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/post-webgpu.js")
407411
endif()
408412

413+
if (onnxruntime_USE_WEBNN)
414+
target_compile_definitions(onnxruntime_webassembly PRIVATE USE_WEBNN=1)
415+
if (NOT onnxruntime_USE_JSEP)
416+
target_link_options(onnxruntime_webassembly PRIVATE
417+
"SHELL:--post-js \"${ONNXRUNTIME_ROOT}/wasm/post-webnn.js\""
418+
)
419+
list(APPEND onnxruntime_webassembly_script_deps "${ONNXRUNTIME_ROOT}/wasm/post-webnn.js")
420+
endif()
421+
endif()
422+
409423
if (onnxruntime_USE_JSEP OR onnxruntime_USE_WEBGPU OR onnxruntime_USE_WEBNN)
410424
# if any of the above is enabled, we need to use the asyncify library
411425
target_link_options(onnxruntime_webassembly PRIVATE
@@ -499,6 +513,9 @@ jsepDownload:_pp_")
499513

500514
if (onnxruntime_USE_JSEP)
501515
string(APPEND target_name ".jsep")
516+
elseif (onnxruntime_USE_WEBGPU OR onnxruntime_USE_WEBNN)
517+
string(APPEND target_name ".asyncify")
518+
# TODO: support JSPI and add ".jspi" once JSPI build is supported
502519
endif()
503520

504521
set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME ${target_name} SUFFIX ".mjs")

js/build_webgpu.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ popd
6969
set PATH=C:\Program Files\Git\usr\bin;%PATH%
7070

7171
call %ROOT%build.bat --config %CONFIG% %CONFIG_EXTRA_FLAG% --skip_submodule_sync --build_wasm --target onnxruntime_webassembly --skip_tests^
72-
--enable_wasm_simd --enable_wasm_threads --use_jsep --use_webnn --use_webgpu --build_dir %BUILD_DIR%
72+
--enable_wasm_simd --enable_wasm_threads --use_webnn --use_webgpu --build_dir %BUILD_DIR%
7373

7474
IF NOT "%ERRORLEVEL%" == "0" (
7575
exit /b %ERRORLEVEL%

js/build_webgpu.sh

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/bin/bash
2+
# Exit immediately if a command exits with a non-zero status.
3+
set -e
4+
5+
# build_webgpu.sh --- build onnxruntime-web with WebGPU EP
6+
#
7+
# Usage:
8+
# build_webgpu.sh config [clean]
9+
#
10+
# Options:
11+
# config Build configuration, "d" (Debug) or "r" (Release)
12+
# clean Perform a clean build (optional)
13+
14+
# Determine the root directory of the project (one level up from the script's directory)
15+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
16+
BUILD_DIR="$ROOT_DIR/build_webgpu"
17+
18+
CONFIG=""
19+
CONFIG_EXTRA_FLAG="" # This will be empty by default
20+
21+
# Parse config argument
22+
if [ "$1" = "d" ]; then
23+
CONFIG="Debug"
24+
CONFIG_EXTRA_FLAG="--enable_wasm_profiling --wasm_run_tests_in_browser --cmake_extra_defines onnxruntime_ENABLE_WEBASSEMBLY_OUTPUT_OPTIMIZED_MODEL=1 --enable_wasm_debug_info"
25+
elif [ "$1" = "r" ]; then
26+
CONFIG="Release"
27+
CONFIG_EXTRA_FLAG="--enable_wasm_api_exception_catching --disable_rtti"
28+
else
29+
echo "Error: Invalid configuration \"$1\"."
30+
echo "Configuration must be 'd' (Debug) or 'r' (Release)."
31+
echo "Usage: $0 [d|r] [clean]"
32+
exit 1
33+
fi
34+
35+
CLEAN_BUILD_REQUESTED=false
36+
if [ "$2" = "clean" ]; then
37+
CLEAN_BUILD_REQUESTED=true
38+
fi
39+
40+
# Perform clean if requested
41+
if [ "$CLEAN_BUILD_REQUESTED" = true ]; then
42+
echo "--- Performing clean build ---"
43+
if [ -d "$BUILD_DIR" ]; then
44+
echo "Removing build directory: $BUILD_DIR"
45+
rm -rf "$BUILD_DIR"
46+
fi
47+
48+
echo "Synchronizing and updating submodules..."
49+
pushd "$ROOT_DIR" > /dev/null
50+
git submodule sync --recursive
51+
git submodule update --init --recursive
52+
popd > /dev/null
53+
fi
54+
55+
# Determine if npm ci needs to be run
56+
# It needs to run if:
57+
# 1. A clean build was requested (which implies js/web/dist will be missing or stale)
58+
# 2. The js/web/dist directory does not exist (e.g., first build or manually removed)
59+
PERFORM_NPM_CI=false
60+
if [ "$CLEAN_BUILD_REQUESTED" = true ]; then
61+
PERFORM_NPM_CI=true
62+
elif [ ! -d "$ROOT_DIR/js/web/dist" ]; then
63+
echo "Directory $ROOT_DIR/js/web/dist not found."
64+
PERFORM_NPM_CI=true
65+
fi
66+
67+
if [ "$PERFORM_NPM_CI" = true ]; then
68+
echo "--- Running npm ci and pulling WASM artifacts ---"
69+
echo "Running npm ci in $ROOT_DIR/js"
70+
pushd "$ROOT_DIR/js" > /dev/null
71+
npm ci
72+
popd > /dev/null
73+
74+
echo "Running npm ci in $ROOT_DIR/js/common"
75+
pushd "$ROOT_DIR/js/common" > /dev/null
76+
npm ci
77+
popd > /dev/null
78+
79+
echo "Running npm ci and pull:wasm in $ROOT_DIR/js/web"
80+
pushd "$ROOT_DIR/js/web" > /dev/null
81+
npm ci
82+
npm run pull:wasm
83+
popd > /dev/null
84+
fi
85+
86+
echo "--- Building WebAssembly modules ---"
87+
88+
echo "Calling $ROOT_DIR/build.sh to build WebAssembly..."
89+
# Note: If $CONFIG_EXTRA_FLAG is empty, it will be omitted from the command due to shell expansion.
90+
"$ROOT_DIR/build.sh" \
91+
--config "$CONFIG" \
92+
--parallel \
93+
${CONFIG_EXTRA_FLAG} \
94+
--skip_submodule_sync \
95+
--build_wasm \
96+
--target onnxruntime_webassembly \
97+
--skip_tests \
98+
--enable_wasm_simd \
99+
--enable_wasm_threads \
100+
--use_webnn \
101+
--use_webgpu \
102+
--build_dir "$BUILD_DIR"
103+
104+
# The 'set -e' command at the beginning of the script ensures that the script will exit
105+
# immediately if the build.sh command (or any other command) fails.
106+
107+
echo "--- Copying build artifacts ---"
108+
# Ensure the dist directory exists before copying files
109+
mkdir -p "$ROOT_DIR/js/web/dist"
110+
111+
echo "Copying ort-wasm-simd-threaded.jsep.wasm to $ROOT_DIR/js/web/dist/"
112+
cp -f "$BUILD_DIR/$CONFIG/ort-wasm-simd-threaded.jsep.wasm" "$ROOT_DIR/js/web/dist/"
113+
114+
echo "Copying ort-wasm-simd-threaded.jsep.mjs to $ROOT_DIR/js/web/dist/"
115+
cp -f "$BUILD_DIR/$CONFIG/ort-wasm-simd-threaded.jsep.mjs" "$ROOT_DIR/js/web/dist/"
116+
117+
echo "--- WebGPU build process completed successfully ---"

js/web/lib/build-def.d.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@ interface BuildDefinitions {
1717
*/
1818
readonly DISABLE_WEBGL: boolean;
1919
/**
20-
* defines whether to disable the whole WebGpu/WebNN backend in the build.
20+
* defines whether to disable the JSEP support in the build.
2121
*/
2222
readonly DISABLE_JSEP: boolean;
23+
/**
24+
* defines whether to disable the WebGPU EP support in the build.
25+
*/
26+
readonly DISABLE_WEBGPU: boolean;
27+
/**
28+
* defines whether to disable the WebNN EP support in the build.
29+
*/
30+
readonly DISABLE_WEBNN: boolean;
2331
/**
2432
* defines whether to disable the whole WebAssembly backend in the build.
33+
*
34+
* When this build flag is set to `true`, only WebGL backend will be available.
2535
*/
2636
readonly DISABLE_WASM: boolean;
2737
/**
@@ -40,13 +50,6 @@ interface BuildDefinitions {
4050
*/
4151
readonly ENABLE_BUNDLE_WASM_JS: boolean;
4252

43-
/**
44-
* defines whether to use WebGPU EP instead of JSEP for WebGPU backend.
45-
*
46-
* This flag requires the corresponding WebAssembly artifact to be built with `--use_webgpu` flag.
47-
*/
48-
readonly USE_WEBGPU_EP: boolean;
49-
5053
// #endregion
5154

5255
// #region Build definitions for ESM

js/web/lib/wasm/wasm-core-impl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ export const initEp = async (env: Env, epName: string): Promise<void> => {
111111
});
112112
}
113113

114+
if (epName === 'webnn' && BUILD_DEFS.USE_WEBGPU_EP) {
115+
// This condition means that `--use_webgpu` and `--use_webnn` flags are both set, and `--use_jsep` is not set.
116+
}
117+
114118
if (!BUILD_DEFS.DISABLE_JSEP) {
115119
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
116120
const initJsep = require('./jsep/init').init;

onnxruntime/wasm/post-webnn.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
//
5+
// This file contains the post-run code for the ORT WebAssembly module. The code in this file will be injected into the
6+
// final module using Emscripten's `--post-js` option.
7+
//
8+
// This file will only be used in build with flag `--use_webnn`.
9+
10+
/**
11+
* This function is called only once when initializing the WebNN backend.
12+
*
13+
* @param params WebNN initialization parameters.
14+
*/
15+
Module["webnnInit"] = (params) => {
16+
// Functions called from EM_ASM need to be assigned in a way that can be minified.
17+
// Functions called via emscripten::val::module_property need to be assigned by name so that the minifier doesn't
18+
// change the name.
19+
20+
const backend = params[0];
21+
[
22+
Module.webnnReserveTensorId,
23+
Module.webnnReleaseTensorId,
24+
Module["webnnEnsureTensor"],
25+
Module.webnnUploadTensor,
26+
Module["webnnDownloadTensor"],
27+
Module["webnnEnableTraceEvent"],
28+
] = params.slice(1);
29+
30+
// This function is called from both JS and an EM_ASM block, it needs both a minifiable name and an explicit name.
31+
Module["webnnReleaseTensorId"] = Module.webnnReleaseTensorId;
32+
Module["webnnUploadTensor"] = Module.webnnUploadTensor;
33+
34+
// Functions called from JS also need to have explicit names.
35+
Module["webnnOnRunStart"] = (sessionId) => {
36+
return backend["onRunStart"](sessionId);
37+
};
38+
Module["webnnOnRunEnd"] = backend["onRunEnd"].bind(backend);
39+
Module["webnnRegisterMLContext"] = (sessionId, mlContext) => {
40+
backend["registerMLContext"](sessionId, mlContext);
41+
};
42+
Module["webnnOnReleaseSession"] = (sessionId) => {
43+
backend["onReleaseSession"](sessionId);
44+
};
45+
Module["webnnCreateMLTensorDownloader"] = (tensorId, type) => {
46+
return backend["createMLTensorDownloader"](tensorId, type);
47+
};
48+
Module["webnnRegisterMLTensor"] = (sessionId, tensor, dataType, shape) => {
49+
return backend["registerMLTensor"](sessionId, tensor, dataType, shape);
50+
};
51+
Module["webnnCreateMLContext"] = (optionsOrGpuDevice) => {
52+
return backend["createMLContext"](optionsOrGpuDevice);
53+
};
54+
Module["webnnRegisterMLConstant"] = (
55+
externalFilePath,
56+
dataOffset,
57+
dataLength,
58+
builder,
59+
desc,
60+
shouldConvertInt64ToInt32
61+
) => {
62+
return backend["registerMLConstant"](
63+
externalFilePath,
64+
dataOffset,
65+
dataLength,
66+
builder,
67+
desc,
68+
Module.MountedFiles,
69+
shouldConvertInt64ToInt32
70+
);
71+
};
72+
Module["webnnRegisterGraphInput"] =
73+
backend["registerGraphInput"].bind(backend);
74+
Module["webnnIsGraphInput"] = backend["isGraphInput"].bind(backend);
75+
Module["webnnRegisterGraphOutput"] =
76+
backend["registerGraphOutput"].bind(backend);
77+
Module["webnnIsGraphOutput"] = backend["isGraphOutput"].bind(backend);
78+
79+
Module["webnnCreateTemporaryTensor"] =
80+
backend["createTemporaryTensor"].bind(backend);
81+
Module["webnnIsGraphInputOutputTypeSupported"] =
82+
backend["isGraphInputOutputTypeSupported"].bind(backend);
83+
};

0 commit comments

Comments
 (0)