| Add a WebAssembly backend for the example 728acaa nandithebull 22h ago | 1 | #!/usr/bin/env bash |
| 2 | # The same Mandelbrot frame from the native kernel and the wasm kernel, |
| 3 | # compared byte for byte. |
| 4 | # |
| 5 | # The point is not that floating point is deterministic in the abstract — it |
| 6 | # is that these two builds go through different compilers, different libm |
| 7 | # implementations (glibc vs emscripten's musl) and different word sizes |
| 8 | # (64-bit vs wasm32), and still have to agree, or "the same V code everywhere" |
| 9 | # is a slogan rather than a fact. |
| 10 | set -euo pipefail |
| 11 | cd "$(dirname "$0")/.." |
| 12 | |
| 13 | [ -f build/libvflutter.so ] || { echo "run ./tool/build.sh first"; exit 1; } |
| 14 | [ -f example/web/vflutter.js ] || { echo "run ./tool/build_wasm.sh first"; exit 1; } |
| 15 | |
| 16 | work="$(mktemp -d)" |
| 17 | trap 'rm -rf "$work"' EXIT |
| 18 | |
| 19 | cat > "$work/native_frame.c" <<'EOF' |
| 20 | #include "vflutter.h" |
| 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
| 23 | int main(int argc, char **argv) { |
| 24 | (void)argc; |
| 25 | const int W = 240, H = 180, ITER = 300; |
| 26 | size_t n = (size_t)W * H * 4; |
| 27 | unsigned char *b = calloc(n, 1); |
| 28 | vf_init(); |
| 29 | vf_mandelbrot(b, n, W, H, -0.5, 0.0, 3.0, ITER, 0, H); |
| 30 | FILE *f = fopen(argv[1], "wb"); |
| 31 | fwrite(b, 1, n, f); |
| 32 | fclose(f); |
| 33 | return 0; |
| 34 | } |
| 35 | EOF |
| 36 | |
| 37 | cc -O2 -I src -o "$work/native_frame" "$work/native_frame.c" -L build -lvflutter |
| 38 | LD_LIBRARY_PATH=build "$work/native_frame" "$work/native.bin" |
| 39 | node tool/test_wasm.mjs "$work/wasm.bin" > /dev/null |
| 40 | |
| 41 | python3 - "$work/native.bin" "$work/wasm.bin" <<'EOF' |
| 42 | import sys |
| 43 | a = open(sys.argv[1], 'rb').read() |
| 44 | b = open(sys.argv[2], 'rb').read() |
| 45 | if len(a) != len(b): |
| 46 | sys.exit(f"FAIL size {len(a)} != {len(b)}") |
| 47 | bad = [(i, x, y) for i, (x, y) in enumerate(zip(a, b)) if x != y] |
| 48 | if bad: |
| 49 | worst = max(abs(x - y) for _, x, y in bad) |
| 50 | print(f"FAIL {len(bad)} of {len(a)} bytes differ (max delta {worst})") |
| 51 | for i, x, y in bad[:5]: |
| 52 | print(f" byte {i} (px {i//4}, ch {i%4}): native={x} wasm={y}") |
| 53 | sys.exit(1) |
| 54 | print(f"ok native and wasm kernels agree on all {len(a)} bytes") |
| 55 | EOF |