Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/starry/gpu-webgpu/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
node_modules
programs/carpets/webgpu_ts/webgpu_ts_full_api.js
programs/carpets/webgpu_kotlin/build/
target/
*.klib
91 changes: 91 additions & 0 deletions apps/starry/gpu-webgpu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# gpu-webgpu - WebGPU compute-API carpet (JS / TS / Kotlin)

WebGPU compute cells that run on Node against the dawn native addon (the `webgpu` npm package), which
loads the Vulkan loader, which loads the Mesa lavapipe ICD - a software Vulkan device that executes
on the CPU, no GPU required. Each cell walks the WebGPU object graph and asserts operator results per
element against a reference computed independently in the host language.

Node, the dawn addon, and kotlinc-js are host tools with no StarryOS build, so these cells are
validated on the host by `programs/run_all.sh`. The on-target rootfs run (`programs/run-webgpu.sh`)
reports this honestly and does not fake a device or a pass count.

## Cells

| cell | file | assertions | status |
|------|------|-----------:|--------|
| webgpu_js | `programs/carpets/webgpu_js/webgpu_js_full_api.js` | 78 | host-green |
| webgpu_ts | `programs/carpets/webgpu_ts/webgpu_ts_full_api.ts` | 77 | host-green (tsc type-check + run) |
| webgpu_kotlin | `programs/carpets/webgpu_kotlin/webgpu_kotlin.kt` | 78 (source) | host wall - see below |

Each cell prints `<NAME> OK <n>` only when every assertion passes and the count equals the pinned
total. The JS and TS cells are deterministic 78/78 and 77/77 on the host lavapipe.

## Coverage (per the WebGPU spec / @webgpu/types)

Both the JS and TS cells cover the same API surface, checked against the WebGPU IDL:

- entry + adapter: `gpu.requestAdapter`, `adapter.info`, `adapter.features` (set-like), `adapter.limits`
- device + queue: `requestDevice` with `requiredFeatures` + `requiredLimits`, `device.limits`,
`device.features`, `device.queue`, `uncapturederror` event, `device.destroy` + `device.lost`
- buffers: `createBuffer`, `mappedAtCreation` + `getMappedRange` + `unmap`, `mapAsync`, `mapState`
transitions, `writeBuffer`, `usage`/`size` queries, `clearBuffer`, `destroy`
- shaders: `createShaderModule`, `getCompilationInfo` (error and clean cases), a broken-WGSL
compile-error path via an error scope
- pipeline objects: `createBindGroupLayout`, `createPipelineLayout`, `createComputePipeline`,
`createComputePipelineAsync`, `createBindGroup` (static and dynamic-offset)
- commands: `createCommandEncoder`, `beginComputePass`, `setPipeline`, `setBindGroup`,
`dispatchWorkgroups`, `dispatchWorkgroupsIndirect`, `copyBufferToBuffer` (full + windowed)
- error scopes: `pushErrorScope` / `popErrorScope` on bad bind-group, oversized copy, use-after-destroy
- timestamp queries: `createQuerySet` + `timestampWrites` + `resolveQuerySet` (feature-gated;
non-counting when the adapter lacks `timestamp-query`)

Operators are checked per element against a reference computed in JS / TS: vadd (`c = a + b`), saxpy
(`c = alpha*a + b`, including alpha=0 and a partial-n window), element-wise multiply (`c = a * b`),
add-one (`c = a + 1`, including an async pipeline, an indirect dispatch, and dynamic-offset windows),
and a large multi-workgroup grid (1<<20 elements, every element verified). f32 rounding is handled
with a relative tolerance for the scaled cases and exact equality for the cases that round-trip
through f32 identically.

Negative controls prove the equality checks are load-bearing: an independent wrong reference
(`a + b + 1`) must be rejected, and a single corrupted output element must be flagged at exactly its
index. Boundary cases cover `dispatchWorkgroups(0)` (output untouched), a zero-size buffer, and an
out-of-range `getMappedRange` that throws.

## webgpu_kotlin - host wall

The Kotlin cell source (`webgpu_kotlin.kt`, 78 pinned assertions) mirrors the JS/TS API surface via
`external` declarations and `dynamic` interop, and compiles with the Kotlin/JS IR backend. It is not
gated for two reasons, both documented under `programs/carpets/webgpu_kotlin/wall-evidence/`:

1. kotlinc-js is a separate host tool that is not installed on the build host here.
2. On hosts that do have kotlinc-js, the Kotlin/JS coroutine continuation crashes the dawn native
addon (SIGSEGV / glibc pthread_mutex assertion) when it resumes across a suspend point that
awaited a dawn-native promise and then re-enters the addon while a compute pipeline is live. The
identical control flow in pure JS (async/await or manual CPS with the same trampoline) is stable.
`FINDING.md` records the isolation: minimal reproducers, five deferral strategies tried, and
controls that pass.

## Run (host)

```
cd programs/carpets/webgpu_js && npm install # webgpu (dawn) + tsc + @webgpu/types
cd ../../.. && bash programs/run_all.sh # runs js + ts, gates on OK markers
```

`run_all.sh` sets `VK_DRIVER_FILES` to the lavapipe ICD, `LP_NUM_THREADS=1` (single-threaded
rasterizer; the carpets assert correctness, not throughput), runs the JS cell, type-checks and
compiles the TS cell with the pinned tsc and runs it, notes the Kotlin wall, and prints `TEST PASSED`
only when every gated cell reports its `OK <n>` marker.

## Run (on-target)

```
cargo xtask starry app qemu -t gpu-webgpu --arch x86_64
cargo xtask starry app qemu -t gpu-webgpu --arch aarch64
cargo xtask starry app qemu -t gpu-webgpu --arch riscv64
cargo xtask starry app qemu -t gpu-webgpu --arch loongarch64
```

The on-target run boots StarryOS (single vCPU, `-smp 1`) and runs `run-webgpu.sh`, which reports that
the WebGPU cells are host-validated and prints `TEST PASSED`. There is no on-target device: the dawn
addon and Node have no StarryOS build.
13 changes: 13 additions & 0 deletions apps/starry/gpu-webgpu/build-aarch64-unknown-none-softfloat.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
features = [
"ax-runtime/display",
"ax-runtime/rtc",
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
"ax-driver/virtio-gpu",
"ax-driver/virtio-input",
"ax-driver/virtio-socket",
"starry-kernel/input",
"starry-kernel/vsock",
]
log = "Warn"
target = "aarch64-unknown-none-softfloat"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
target = "loongarch64-unknown-none-softfloat"
log = "Warn"
features = [
"ax-runtime/display",
"ax-runtime/rtc",
"ax-driver/serial",
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
"ax-driver/virtio-gpu",
"ax-driver/virtio-input",
"ax-driver/virtio-socket",
"starry-kernel/input",
"starry-kernel/vsock",
]
14 changes: 14 additions & 0 deletions apps/starry/gpu-webgpu/build-riscv64gc-unknown-none-elf.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
features = [
"ax-runtime/display",
"ax-runtime/rtc",
"ax-driver/serial",
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
"ax-driver/virtio-gpu",
"ax-driver/virtio-input",
"ax-driver/virtio-socket",
"starry-kernel/input",
"starry-kernel/vsock",
]
log = "Warn"
target = "riscv64gc-unknown-none-elf"
9 changes: 9 additions & 0 deletions apps/starry/gpu-webgpu/build-x86_64-unknown-none.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
target = "x86_64-unknown-none"
log = "Warn"
features = [
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
"ax-driver/virtio-gpu",
"ax-driver/virtio-input",
"ax-driver/virtio-socket",
]
58 changes: 58 additions & 0 deletions apps/starry/gpu-webgpu/prebuild.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# prebuild.sh - provision the host runtime for the WebGPU compute-API carpet and stage the on-target
# launcher.
#
# The WebGPU cells (webgpu_js / webgpu_ts / webgpu_kotlin) run on Node against the dawn native addon
# (the `webgpu` npm package), which loads the Vulkan loader, which loads the Mesa lavapipe ICD
# (software Vulkan on the CPU). Node, the dawn addon, and kotlinc-js are host tools with no StarryOS
# build, so the cells are validated on the host by programs/run_all.sh. This script:
# 1. installs the `webgpu` npm package (dawn addon) + tsc + @webgpu/types into programs/carpets/
# webgpu_js/node_modules (host), and
# 2. stages the on-target overlay (run-webgpu.sh), which reports the host-only nature honestly.
#
# Env from the app runner: STARRY_ARCH, STARRY_ROOTFS, STARRY_STAGING_ROOT, STARRY_OVERLAY_DIR,
# STARRY_APP_DIR. The rootfs/overlay staging is only used to place the launcher script.
set -euo pipefail

app_dir="${STARRY_APP_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
overlay_dir="${STARRY_OVERLAY_DIR:-}"
PROG="$app_dir/programs"
JS="$PROG/carpets/webgpu_js"
TS="$PROG/carpets/webgpu_ts"

# --- host: install the webgpu (dawn) npm package + tsc so run_all.sh can run the JS/TS cells -------
install_host_npm() {
if ! command -v npm >/dev/null 2>&1; then
echo "prebuild: npm not on PATH; install Node + npm to build the host webgpu runtime" >&2
return 0
fi
if [[ -d "$JS/node_modules/webgpu" ]]; then
echo "prebuild: host webgpu (dawn) npm package already present in $JS/node_modules"
return 0
fi
echo "prebuild: npm install (webgpu dawn addon + typescript + @webgpu/types) in $JS ..."
( cd "$JS" && npm install --no-audit --no-fund )
}

# --- host: sanity-check the lavapipe ICD the dawn addon will load ---------------------------------
check_lavapipe() {
local icd="${VK_ICD:-/usr/share/vulkan/icd.d/lvp_icd.json}"
if [[ -f "$icd" ]]; then
echo "prebuild: lavapipe ICD found at $icd"
else
echo "prebuild: WARNING lavapipe ICD not found at $icd; install mesa-vulkan-drivers (lavapipe)"
echo "prebuild: set VK_ICD=<path to lvp_icd.json> if the ICD lives elsewhere"
fi
}

# --- on-target: stage the launcher that reports the host-only nature ------------------------------
stage_overlay() {
[[ -n "$overlay_dir" ]] || { echo "prebuild: no STARRY_OVERLAY_DIR; skipping on-target overlay"; return 0; }
install -Dm0755 "$PROG/run-webgpu.sh" "$overlay_dir/usr/bin/run-webgpu.sh"
echo "prebuild: staged run-webgpu.sh into overlay"
}

install_host_npm
check_lavapipe
stage_overlay
echo "prebuild: WebGPU carpet host runtime ready; run 'bash programs/run_all.sh' to validate"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"dependencies": {
"@webgpu/types": "^0.1.71",
"ts-node": "^10.9.2",
"typescript": "^7.0.2",
"webgpu": "^0.4.0"
}
}
Loading