Skip to content

Commit 09bdeaa

Browse files
authored
Merge pull request #85 from AnswerDotAI/simplify-browser-builds
Simplify browser builds and SPIR-V testing
2 parents b8e5d96 + 0246970 commit 09bdeaa

7 files changed

Lines changed: 50 additions & 22 deletions

File tree

‎.github/workflows/build.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ jobs:
1414
runs-on: ${{ matrix.os }}
1515
steps:
1616
- uses: actions/checkout@v4
17+
- uses: actions/setup-python@v7
18+
with:
19+
python-version: "3.13"
1720
- if: runner.os == 'Linux'
1821
run: |
1922
sudo apt-get update

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ browser target.
3535
- The legacy raw WebGPU C API implementation, manual resource pools, custom
3636
half implementation, Haskell binding, obsolete build files, and abandoned
3737
experimental targets.
38+
- The Closure compiler and Java dependency from browser builds.

‎CMakeLists.txt‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ if(EMSCRIPTEN)
3030
endif()
3131
target_compile_options(gpucpp INTERFACE "${EMDAWN_PORT}" "-fwasm-exceptions")
3232
target_link_options(gpucpp INTERFACE "${EMDAWN_PORT}" "-fwasm-exceptions"
33-
"-sJSPI=1" "--closure=1")
34-
if(CMAKE_HOST_APPLE)
35-
target_link_options(gpucpp INTERFACE "--closure-args=--platform=java")
36-
endif()
33+
"-sJSPI=1")
3734
else()
3835

3936
set(GPUCPP_DAWN_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/dawn" CACHE PATH

‎DEV.md‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ The same file pins the emsdk revision and Emscripten version recorded in
1111
Dawn's DEPS. `tools/build_emdawn.sh` builds `emdawnwebgpu_pkg` from that exact
1212
Dawn source and stages its local Emscripten port under
1313
`third_party/emdawnwebgpu/`. The sibling `../emsdk` clone and staged package are
14-
not committed. Closure is required by Emdawn release links and uses OpenJDK on
15-
macOS ARM.
14+
not committed.
1615

1716
The top-level build fetches the tagged pybind11 release declared in
1817
`CMakeLists.txt`; consumers using only the C++ target do not fetch or build it.
@@ -69,9 +68,9 @@ local release path.
6968
`./test --web` cross-compiles the same public core and Embind API against
7069
Emdawnwebgpu, opens the result with `emrun`, and checks rejected invalid WGSL,
7170
context reuse, typed-array upload, dispatch, and readback in Chrome. The
72-
release build uses Closure, Wasm exceptions, and JSPI. CI uses
73-
`./test --build-web` to compile the same artifacts without requiring a browser
74-
GPU; the complete story remains the local runtime contract.
71+
release build uses Wasm exceptions and JSPI. CI uses `./test --build-web` to
72+
compile the same artifacts without requiring a browser GPU; the complete story
73+
remains the local runtime contract.
7574

7675
## Architecture
7776

‎README.md‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ Dawn library, and stages its headers, library, and `spirv-as` under
2727
and build trees under `third_party/local/dawn/` directly.
2828

2929
Browser builds require Chrome with WebGPU and JSPI, plus a sibling `../emsdk`
30-
clone. On macOS they also require OpenJDK for Closure:
30+
clone:
3131

3232
```bash
3333
git clone --depth 1 https://github.com/emscripten-core/emsdk.git ../emsdk
34-
brew install openjdk
3534
./test --rebuild-web
3635
```
3736

@@ -132,6 +131,23 @@ target_link_libraries(my_program PRIVATE gpucpp)
132131
See [DEV.md](DEV.md) for the dependency layout and update process, and
133132
[CHANGELOG.md](CHANGELOG.md) for release notes.
134133

134+
Browser consumers can supply their own Embind surface while inheriting the
135+
Emdawnwebgpu, Wasm-exception, and JSPI settings from `gpucpp`:
136+
137+
```cmake
138+
add_subdirectory(path/to/gpu.cpp EXCLUDE_FROM_ALL)
139+
add_executable(my_web_app app.cpp)
140+
set_target_properties(my_web_app PROPERTIES SUFFIX ".js")
141+
target_link_libraries(my_web_app PRIVATE gpucpp)
142+
target_link_options(my_web_app PRIVATE "--bind" "--no-entry"
143+
"-sMODULARIZE=1" "-sEXPORT_NAME=createModule" "-sENVIRONMENT=web"
144+
"-sALLOW_MEMORY_GROWTH=1")
145+
```
146+
147+
The Embind functions that call `createContext()`, `wait()`, or browser-facing
148+
helpers containing them must use `emscripten::async()` so JSPI can suspend the
149+
Wasm stack.
150+
135151
## Python
136152

137153
Install the self-contained macOS ARM64 wheel from PyPI with `pip install

‎test‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
external_spirv=
45
if [[ ${1:-} == --web || ${1:-} == --build-web || \
56
${1:-} == --rebuild-web ]]; then
67
if [[ ${1:-} == --rebuild-web || \
@@ -9,15 +10,6 @@ if [[ ${1:-} == --web || ${1:-} == --build-web || \
910
fi
1011
export EMSDK_QUIET=1
1112
source "${GPUCPP_EMSDK_ROOT:-../emsdk}/emsdk_env.sh" >/dev/null
12-
if [[ $(uname -s) == Darwin ]]; then
13-
if [[ -x /opt/homebrew/opt/openjdk/bin/java ]]; then
14-
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
15-
fi
16-
if ! java -version >/dev/null 2>&1; then
17-
echo "Closure requires Java on macOS; install it with brew install openjdk" >&2
18-
exit 1
19-
fi
20-
fi
2113
emcmake cmake -S . -B build-web -G Ninja -DCMAKE_BUILD_TYPE=Release
2214
cmake --build build-web --target gpu_cpp_web web_binding_test
2315
if [[ ${1:-} != --build-web ]]; then
@@ -26,8 +18,10 @@ if [[ ${1:-} == --web || ${1:-} == --build-web || \
2618
exit
2719
elif [[ ${1:-} == --rebuild-dawn ]]; then
2820
tools/build_dawn.sh
21+
elif [[ ${1:-} == --spirv && $# -eq 2 ]]; then
22+
external_spirv=$2
2923
elif [[ $# -ne 0 ]]; then
30-
echo "usage: ./test [--rebuild-dawn|--web|--build-web|--rebuild-web]" >&2
24+
echo "usage: ./test [--rebuild-dawn|--web|--build-web|--rebuild-web|--spirv FILE]" >&2
3125
exit 2
3226
elif [[ ! -f third_party/dawn/include/dawn/webgpu_cpp.h &&
3327
! -f third_party/local/dawn/build-latest/gen/include/dawn/webgpu_cpp.h ]]; then
@@ -37,3 +31,6 @@ fi
3731
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
3832
cmake --build build
3933
ctest --test-dir build --output-on-failure
34+
if [[ -n $external_spirv ]]; then
35+
build/gpu_test build/write42.spv "$external_spirv"
36+
fi

‎tests/gpu_test.cpp‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ static void expect(const std::vector<T> &actual,
5151
}
5252

5353
int main(int argc, char **argv) {
54-
if (argc != 2) throw std::runtime_error("expected assembled SPIR-V path");
54+
if (argc != 2 && argc != 3)
55+
throw std::runtime_error("expected assembled SPIR-V path");
5556

5657
// Ordinary WGSL covers upload, explicit binding access, dispatch, and readback.
5758
auto context = createContext();
@@ -98,5 +99,19 @@ int main(int argc, char **argv) {
9899
wait(spirvContext, answerDownloaded);
99100
expect(answer, std::vector<int32_t>{42}, "SPIR-V compute");
100101

102+
if (argc == 3) {
103+
std::vector<int32_t> externalAnswer(1);
104+
auto externalOutput = createTensor(spirvContext, {1}, ki32);
105+
auto external = createKernel(
106+
spirvContext, SPIRV{readSPIRV(argv[2]), "external SPIR-V", "main"},
107+
Bindings{readWrite(externalOutput)});
108+
auto externalDispatched = dispatchKernel(spirvContext, external);
109+
wait(spirvContext, externalDispatched);
110+
auto externalDownloaded =
111+
toCPU(spirvContext, externalOutput, externalAnswer);
112+
wait(spirvContext, externalDownloaded);
113+
expect(externalAnswer, std::vector<int32_t>{42}, "external SPIR-V compute");
114+
}
115+
101116
std::cout << "WGSL, f16, and SPIR-V compute stories passed\n";
102117
}

0 commit comments

Comments
 (0)